This is an R Markdown
Notebook. When you execute code within the notebook, the results appear
beneath the code.
Try executing this chunk by clicking the Run button within
the chunk or by placing your cursor inside it and pressing
Cmd+Shift+Enter.
Add a new chunk by clicking the Insert Chunk button on the
toolbar or by pressing Cmd+Option+I.
When you save the notebook, an HTML file containing the code and
output will be saved alongside it (click the Preview button or
press Cmd+Shift+K to preview the HTML file).
The preview shows you a rendered HTML copy of the contents of the
editor. Consequently, unlike Knit, Preview does not
run any R code chunks. Instead, the output of the chunk when it was last
run in the editor is displayed.
Import necessary libraries
library(tidyverse)
── Attaching core tidyverse packages ──────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.4 ✔ readr 2.1.5
✔ forcats 1.0.0 ✔ stringr 1.5.1
✔ ggplot2 3.5.1 ✔ tibble 3.2.1
✔ lubridate 1.9.3 ✔ tidyr 1.3.1
✔ purrr 1.0.2
── Conflicts ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
Importing necesary CSV files
#Setting working directory
setwd("/Users/tammyray/Desktop/Aaron_16p_Imaging_Transcriptomics/CSV_data_sheets/transcriptomic_datasheets")
Warning: The working directory was changed to /Users/tammyray/Desktop/Aaron_16p_Imaging_Transcriptomics/CSV_data_sheets/transcriptomic_datasheets inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
#Importing trancriptomic datasdets
Talkowski2014 <- read.csv("Talkowski_2014_TableS3_Human_Del.csv")
Urresti2021_3M_organoid <- read.csv("Urresti-2021_DEG-3M-cortical-organoid.csv")
Roth2020 <- read.csv("Roth_2020_DEG-hIPSC-neural-endodermMesoderm.csv")
#Importing file containing 16p11.2 gene list
chr16p11.2_gene_list_Kusenda2015 <- read.csv("Kusenda_2015_TableS1_16p11.2_gene_list.csv")
#Creating a vector of all genes in the 16p11.2 chromosomal region
sixteenP11.2_genes <- chr16p11.2_gene_list_Kusenda2015$Gene.symbol
Modifying dataframes, such that they have the same column names, in
order to combine them
- Uresti 2021 cortical organoids data
Urresti2021_3M_organoid_tidy <- Urresti2021_3M_organoid %>%
#remove columns that i do not need
select(-c("Gene.Biotype", "log2.FC..DUP.vs.DEL", "P.value..DUP.vs.DEL", "FDR.adjusted.P.value..DUP.vs.DEL", "log2.FC..DUP.vs.CTL",
"P.value..DUP.vs.CTL", "FDR.adjusted.P.value..DUP.vs.CTL", "FDR.adjusted.P.value..DEL.vs.CTL")) %>%
#rename columns to the standardized names I decided on
rename("gene_name" = "HGNC.Symbol",
"log2_fold_change" = "log2.FC..DEL.vs.CTL",
"p_value" = "P.value..DEL.vs.CTL",
"gene_description" = "Description",
"ENSEMBL_ID" = "ENSEMBL.ID") %>%
#add a column for the data source
mutate( "sample_type" = "cortical organoid", "data_source" = "Urresti et al. 2021", "Present.in.the.16p11.2.Region" = "") %>%
#reorder columns so that the ensemble_ID column, which not all dataframes will have, is at the end
relocate("ENSEMBL_ID", .after = "data_source")
- Roth 2020 data
Roth2020_tidy <- Roth2020 %>%
# remove columns that I do not need
select(-c("SFARI.Gene.Score", "SFARI.Gene.Score.Category", "https...gene.sfari.org.about.gene.scoring.criteria.")) %>%
#rename columns to the standardized names I decided on
rename("gene_name" = "X16p11.2.DE.Genes",
"log2_fold_change" = "Log2.Fold.Change..Positive.values.are.upregulated.in.DEL.",
"p_value" = "Adjusted.P.Value") %>%
#add columns for the data source, sample type, and extras to match the above dataset
mutate("gene_description" = "", "sample_type" = "hIPSC", "data_source" = "Roth et al. 2020", "ENSEMBL_ID" = "") %>%
#reorder columns to match the other dataframes
relocate("gene_description", .after = "gene_name") %>%
relocate("Present.in.the.16p11.2.Region", .after = "ENSEMBL_ID")
- Talkowski 2014 data
Talkowski2014_tidy <- Talkowski2014 %>%
select(-c("GeneInfo", "Chr", "Start", "Stop")) %>%
#select(-c("GeneInfo", "Chr", "Start", "Stop")) %>%
#Transforming the foldchange to log2 foldchange
mutate("FoldChange" = log2(FoldChange)) %>%
#rename columns to the standardized names I decided on
rename("gene_name" = "GeneID",
"log2_fold_change" = "FoldChange",
"p_value" = "permPval_Del") %>%
#add columns for the data source, sample type, and extras to match the above dataset
mutate("gene_description" = "", "sample_type" = "hLCL", "data_source" = "Talkowski et al. 2014", "ENSEMBL_ID" = "", "Present.in.the.16p11.2.Region" = "") %>%
#reorder columns to match the other dataframes
relocate("gene_description", .after = "gene_name") %>%
relocate("p_value", .after = "log2_fold_change")
Potential next step: I tried to add in the ensembl ID for the
Talkowski 2014 data, but that dataset used an old refrence transcriptome
and so, using the chromosomal start and stop positions and chromosome
number, I was unable to find the ensembl ID for the genes in that
dataset. I
Now, I want to fill in the “Present.in.the.16p11.2.Region” column for
the DEG_all_timepoints_organoid_Urresti2021_modified_columns
dataframe.
# The vector sixteenP11.2_genes is a vector containing all genes located in the 16p11.2 chromosomal region
# I want to change the value of the "Present.in.the.16p11.2.Region" column to "Yes" if the gene name is in the vector, and "No" if it is not
Urresti2021_3M_organoid_tidy$Present.in.the.16p11.2.Region <-
ifelse(Urresti2021_3M_organoid_tidy$gene_name %in% sixteenP11.2_genes, "Yes", "No")
Roth2020_tidy$Present.in.the.16p11.2.Region <-
ifelse(Roth2020_tidy$gene_name %in% sixteenP11.2_genes, "Yes", "No")
Talkowski2014_tidy$Present.in.the.16p11.2.Region <-
ifelse(Talkowski2014_tidy$gene_name %in% sixteenP11.2_genes, "Yes", "No")
Now I combine all 3 organized dataframes into 1 dataframe
all_DEG_data <- rbind(Urresti2021_3M_organoid_tidy, Roth2020_tidy, Talkowski2014_tidy)
# Now, I want to look at the genes in the 16p11.2 region only, from the all DEG data. So I will filter the all_DEG_data dataframe to only include those genes
all_DEG_16p_genes <- all_DEG_data %>%
filter(Present.in.the.16p11.2.Region == "Yes")
No I will do a metaanalysis to combine every instance of a gene into
one row, so that I can see all the data for each gene in one row Log
fold change is weighted by p-value p values are combined with fishers
exact test
meta_analysis_all_DEG_data <- all_DEG_data %>%
group_by(gene_name) %>%
summarize(combined_log2_fold_change = sum(log2_fold_change / (p_value + 1e-8)) / sum(1 / (p_value + 1e-8)), # Weighted logFC using p-values.
# A small constant (1e-8) is added to avoid division by zero if there are very small p-values.
#in the next line of code I will do a fisher test to combine the p-values
combined_p_value = 1 - pchisq(sum(qchisq(1 - p_value, 1, lower.tail = FALSE)), length(p_value), lower.tail = FALSE)) %>%
#the above code will return a dataframe that only contains 3 of the columns. In the next line of code I will bring the rest of the columns back to this new dataframe
left_join(all_DEG_data, by = "gene_name")
#Keep track of if the gene combined logfoldcahnge and p-value are from multiple data sources
meta_analysis_all_DEG_data$multiple_data_sources <- ifelse(duplicated(meta_analysis_all_DEG_data$gene_name) | duplicated(meta_analysis_all_DEG_data$gene_name, fromLast = TRUE), "Yes", "No")
#Now, I want to delete rows that have the same gene name and remove the columns that have the original log2_fold_change, p_value, sample_type, and data_source
meta_analysis_all_DEG_data <- meta_analysis_all_DEG_data %>%
distinct(gene_name, .keep_all = TRUE) %>%
select(-c(log2_fold_change, p_value, sample_type, data_source))
#This code adds a column called significance that will indicate the degree of significance, just like Smrithi's code
meta_analysis_all_DEG_data <- meta_analysis_all_DEG_data %>%
mutate("significance" = case_when(
combined_p_value < 0.001 ~ "***",
combined_p_value < 0.01 ~ "**",
combined_p_value < 0.05 ~ "*",
TRUE ~ " "
))
#Now i will create a new dataframe with only the genes that are significantly differentially expressed at combined p-value < 0.001
sig_genes_p0.001_DEG_data <- meta_analysis_all_DEG_data %>%
filter(significance == "***")
Exporting the dataframes to CSV files, if desired
setwd("/Users/tammyray/Desktop/aaron_lab_2024/output")
write.csv(Urresti2021_3M_organoid_tidy, file="Urresti2021_3M_organoid_tidy.csv")
write.csv(Roth2020_tidy, file="Roth2020_tidy.csv")
write.csv(Talkowski2014_tidy, file="Talkowski2014_tidy.csv")
write.csv(all_DEG_data, file="all_DEG_data.csv")
write.csv(meta_analysis_all_DEG_data, file="meta_analysis_all_DEG_data.csv")
write.csv(sig_genes_p0.001_DEG_data, file="sig_genes_p0.001_DEG_data.csv")
Gene ontology analysis I am using gprofiler2 to do my GO analysis
Loading gprofiler2 package
library(gprofiler2)
Doing GO analysis
up_reg_genes <- ssig_genes_p0.001_DEG_data %>% filter(combined_log2_fold_change > 0)
Error: object 'ssig_genes_p0.001_DEG_data' not found
Exporting the GO analysis dataframes to CSV files, if desired
setwd("/Users/tammyray/Desktop/aaron_lab_2024/output")
write.csv(gostres_results, file="/Users/tammyray/Desktop/Aaron_16p_Imaging_Transcriptomics/output/GO_16p11.2-DEGs_p0.001_fdr-corrections.csv", row.names = FALSE)
NOW, we generate map of our significant genes to AHBA spatial map
First, read in the data
AHBA <- read_tsv("/Users/tammyray/Desktop/Aaron_16p_Imaging_Transcriptomics/CSV_data_sheets/AllenHBA_DK_ExpressionMatrix.tsv")
New names:
• `` -> `...1`
Rows: 20736 Columns: 70
── Column specification ─────────────────────────────────────────────────────────────────────────────────────────
Delimiter: "\t"
chr (1): ...1
dbl (69): Average donor correlation to median, ctx-rh-insula, ctx-lh-paracentral, ctx-rh-precuneus, ctx-lh-me...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Now, I want to cchange the column header of the first column of the AHBA dataframe to gene_symbol
colnames(AHBA)[1] <- "gene_symbol"
Mapping our significant genes to the AHBA dataset
#Creating vector of gene names in our experimental groups
sig_genes_p0.001_DEG_data #dataframe containing all significant genes
sig_gene_list <- sig_genes_p0.001_DEG_data$gene_name #vector of all significant genes names
sixteenP11.2_genes #dataframe containing all genes in 16p11.2 locus
sixteen_p_11.2_genes <- chr16p11.2_gene_list_Kusenda2015$Gene.symbol #vector of all genes in 16p locus
AHBA_sig_genes <- AHBA %>% filter(gene_symbol %in% sig_gene_list)
#NOTE: not all sig genes mapped to AHBA dataset. Here is a list of them so I can troubleshoot later
genes_not_mapped <- sig_gene_list[!(sig_gene_list %in% AHBA_sig_genes$gene_symbol)]
NOTE: Only 87 of the 132 genes mapped to the AHBA dataset
Tidying the AHBA subset dataframe with significant genes only
AHBA_sig_genes_pivot <- AHBA_sig_genes %>%
#remove the "Average donor correlation to the median" column
select(-"Average donor correlation to median") %>%
pivot_longer(cols = -gene_symbol, names_to = "region", values_to = "expression") %>%
#adding a column for if gene is in the 16p region
mutate(in_16p_region = ifelse(gene_symbol %in% sixteen_p_11.2_genes, "Yes", "No")) %>%
# Adding a column for if gene is up or downregulated
mutate(upreg = ifelse(gene_symbol %in% up_reg_gene_names, "Yes", "No"))
GGplot to visualize the data
# Visualizing expression data of significant genes
ggplot(AHBA_sig_genes_pivot, aes(x=expression, y=region, shape=in_16p_region, color=gene_symbol)) +
geom_point() +
labs(title = "regional expression of significant genes from 16p del meta-analysis", x = "Raw Expression", y = "Brain Region") +
theme_minimal() +
#I will make the legend smaller and put it underneath the graph because it is too big
theme(legend.position = "bottom") +
guides(color="none")

# same plot but aesthetics only for genes in 16p region
ggplot(AHBA_sig_genes_pivot, aes(x=expression, y=region, color=in_16p_region)) +
geom_point() +
labs(title = "regional expression of significant genes from 16p del meta-analysis", x = "Raw Expression", y = "Brain Region") +
theme_minimal() +
#I will make the legend smaller and put it underneath the graph because it is too big
theme(legend.position = "bottom")

ggplot(AHBA_sig_genes_pivot, aes(x=expression, y=region, color=upreg)) +
geom_point() +
labs(title = "regional expression of significant genes from 16p del meta-analysis", x = "Raw Expression", y = "Brain Region") +
theme_minimal() +
#I will make the legend smaller and put it underneath the graph because it is too big
theme(legend.position = "bottom")

Now, we want to work with the normalized AHBA values. They are in a
matlab file, so first I will need to convert the matlab file to
something R can read, with the R.matlab package. NOTE: The R.matlab
package does not keep column names of the original data when converting
things, so I had to add them back in.
First, load libraries
library(R.matlab)
R.matlab v3.7.0 (2022-08-25 21:52:34 UTC) successfully loaded. See ?R.matlab for help.
Attaching package: ‘R.matlab’
The following objects are masked from ‘package:base’:
getOption, isOpen
Second, load in relevant files
setwd("/Users/tammyray/Desktop/Aaron_16p_Imaging_Transcriptomics")
AHBA_normed <- readMat("ROIxGene_aparcaseg_INT.mat")
setwd("/Users/tammyray/Desktop/Aaron_16p_Imaging_Transcriptomics/CSV_data_sheets")
region_array <- read_csv("Region_labels_for_aparcaseg_parcellation.csv", col_names = FALSE)
Tidying up the AHBA_normed dataframe
#Yay now data table is as i want it to be!
# Now I will pivot the table so that it matches the AHBA_sig_genes_all_pivot table
AHBA_normed_pivot <- AHBA_parcel_expression0_labeled %>%
pivot_longer(cols = -region, names_to = "gene_symbol", values_to = "expression") %>%
mutate(in_16p_region = ifelse(gene_symbol %in% sixteen_p_11.2_genes, "Yes", "No")) %>%
unnest(cols = region)
AHBA_normed_pivot_sigONLY <- AHBA_normed_pivot %>%
filter(gene_symbol %in% gene_list_all)
Error in `filter()`:
ℹ In argument: `gene_symbol %in% gene_list_all`.
Caused by error:
! object 'gene_list_all' not found
Backtrace:
1. AHBA_normed_pivot %>% filter(gene_symbol %in% gene_list_all)
9. gene_symbol %in% gene_list_all
Exporting dataframes as CSVs
# OK, Now that I have this data, I want to put it into a CSV so I have it for future reference
setwd("/Users/tammyray/Desktop/aaron_lab_2024/output")
write.csv(AHBA_normed_pivot, "Normed_AHBA_sig_genes.csv")
write.csv(AHBA_normed_pivot_sigONLY, "Normed_AHBA_sig_genes_ONLY.csv")
write.csv(AHBA_sig_genes_all_pivot_ONLY, "Raw_AHBA_sig_genes_ONLY.csv")
Plotting the normalized AHBA data
ggplot(AHBA_normed_pivot_sigONLY, aes(x=expression, y=region, color=gene_symbol)) +
geom_point() +
labs(title = "NORMALIZED regional expression of significant genes from 16p del meta-analysis", x = "Normalized Expression", y = "Brain Region") +
theme_minimal() +
#I will remove the legend because it is too big
theme(legend.position = "none")

# Visualizing expression data of significant genes
ggplot(AHBA_normed_pivot_sigONLY, aes(x=expression, y=region, shape=in_16p_region, color=gene_symbol)) +
geom_point() +
labs(title = "NORMALIZED regional expression of significant genes from 16p del meta-analysis", x = "Normalized Expression", y = "Brain Region") +
theme_minimal() +
#I will make the legend smaller and put it underneath the graph because it is too big
theme(legend.position = "bottom") +
guides(color="none")

# same plot but aesthetics only for genes in 16p region
ggplot(AHBA_normed_pivot_sigONLY, aes(x=expression, y=region, color=in_16p_region)) +
geom_point() +
labs(title = "NORMALIZED regional expression of significant genes from 16p del meta-analysis", x = "Normalized Expression", y = "Brain Region") +
theme_minimal() +
#I will make the legend smaller and put it underneath the graph because it is too big
theme(legend.position = "bottom")

Now I will map the normalized AHBA data to Smrithi’s MRI data, which
is in a csv file: 16panalysis_BH_adjusted.csv
Importing necessary files
# Importing Smrithi's MRI dataset
setwd("/Users/tammyray/Desktop/aaron_lab_2024/output")
Warning: The working directory was changed to /Users/tammyray/Desktop/aaron_lab_2024/output inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
MRI <- read_csv("16panalysis_BH_adjusted.csv")
Rows: 1224 Columns: 10
── Column specification ────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (4): Genotype, Model, VolumetricComponent, Significance
dbl (6): Estimate, Std. Error, t value, Pr(>|t|), SigPos, adjusted_p
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Outside of R, I have made a CSV of corresponding AHBA and Smrithi MRI data region names. First column is AHBA names, second column is MRI names.
# Importing the data
setwd("/Users/tammyray/Desktop/aaron_lab_2024/CSV_data_sheets")
standard_region_names <- read_csv("AHBA_MRI_region_names.csv")
Rows: 34 Columns: 2
── Column specification ────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): AHBA regions, left hemisphere Smrithi regions
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Remembering other files I will use in the following chunks
sixteen_p_11.2_genes #vector of all genes in 16p locus
[1] "SLC7A5P1" "SPN" "QPRT" "C16orf54" "ZG16" "KIF22" "MAZ"
[8] "PRRT2" "C16orf53" "MVP" "CDIPT" "LOC440356" "SEZ6L2" "ASPHD1"
[15] "KCTD13" "TMEM219" "TAOK2" "HIRIP3" "INO80E" "DOC2A" "C16orf92"
[22] "FAM57B" "ALDOA" "PPP4C" "TBX6" "YPEL3" "GDPD3" "MAPK3"
[29] "CORO1A" "BOLA2" "SLX1A" "SULT1A3" "IMMA" "SMG1 "
Tidying Smrithi’s MRI data
# We decided that we only want to use model 3, Spline TCV model (decided w Smrithi meeting 8/24/24)
# We are only using the deletion data for now
MRI_model3 <- MRI %>%
filter(Genotype == "Genotype16pDeletion...5")
#MRI regions to remove. I made this list manually using google sheets and reformatted it for R using chatgpt
MRI_regions_to_remove <- c("L.Cerebral_WM", "L.cerebral_cortex", "L.lateral_ventricle", "L.inferior_lateral_ventricle", "L.cerebellum_WM", "L.cerebellum_cortex",
"L.thalamus", "L.caudate", "L.putamen", "L.pallidum", "L.accumbens", "L.hippocampus", "L.amygdala", "L.ventral_DC", "Third_Ventricle",
"Fourth_Ventricle", "Brainstem", "CSF", "R.Cerebral_WM", "R.cerebral_cortex", "R.lateral_ventricle", "R.inferior_lateral_ventricle",
"R.cerebellum_WM", "R.cerebellum_cortex", "R.thalamus", "R.caudate", "R.putamen", "R.pallidum", "R.hippocampus", "R.amygdala", "R.accumbens",
"R.ventral_DC", "R.ctx_bankssts", "R.ctx_caudalanteriorcingulate", "R.ctx_caudalmiddlefrontal", "R.ctx_cuneus", "R.ctx_entorhinal", "R.ctx_fusiform",
"R.ctx_inferiorparietal", "R.ctx_inferiortemporal", "R.ctx_isthmuscingulate", "R.ctx_lateraloccipital", "R.ctx_lateralorbitofrontal", "R.ctx_lingual",
"R.ctx_medialorbitofrontal", "R.ctx_middletemporal", "R.ctx_parahippocampal", "R.ctx_paracentral", "R.ctx_parsopercularis", "R.ctx_parsorbitalis",
"R.ctx_parstriangularis", "R.ctx_pericalcarine", "R.ctx_postcentral", "R.ctx_posteriorcingulate", "R.ctx_precentral", "R.ctx_precuneus",
"R.ctx_rostralanteriorcingulate", "R.ctx_rostralmiddlefrontal", "R.ctx_superiorfrontal", "R.ctx_superiorparietal", "R.ctx_superiortemporal",
"R.ctx_supramarginal", "R.ctx_frontalpole", "R.ctx_temporalpole", "R.ctx_transversetemporal", "R.ctx_insula", "cGMV", "WMV", "sGMV", "Ventricles",
"Cerebellum", "Accumbens", "Ventral_Diencephalon", "Pallidum", "Hippocampus", "Caudate", "Cerebral_White_Matter", "Lateral_Ventricle", "Cerebral_Cortex",
"Thalamus", "Putamen", "Amygdala", "Cerebellar_White_Matter", "Cerebellar_Cortex", "Inferior_Lateral_Ventricle", "ctx_bankssts", "ctx_caudalanteriorcingulate",
"ctx_caudalmiddlefrontal", "ctx_cuneus", "ctx_entorhinal", "ctx_fusiform", "ctx_inferiorparietal", "ctx_inferiortemporal", "ctx_isthmuscingulate",
"ctx_lateraloccipital", "ctx_lateralorbitofrontal", "ctx_lingual", "ctx_medialorbitofrontal", "ctx_middletemporal", "ctx_parahippocampal",
"ctx_paracentral", "ctx_parsopercularis", "ctx_parsorbitalis", "ctx_parstriangularis", "ctx_pericalcarine", "ctx_postcentral", "ctx_posteriorcingulate",
"ctx_precentral", "ctx_precuneus", "ctx_rostralanteriorcingulate", "ctx_rostralmiddlefrontal", "ctx_superiorfrontal", "ctx_superiorparietal",
"ctx_superiortemporal", "ctx_supramarginal", "ctx_frontalpole", "ctx_temporalpole", "ctx_transversetemporal", "ctx_insula")
# removing rows for the regions we aren't including
MRI_model3_leftHem <- MRI_model3 %>%
filter(VolumetricComponent %in% MRI_regions_to_remove == FALSE) %>%
rename(region = VolumetricComponent)
# Now, I want to use the standard region
standard_region_names <- standard_region_names %>%
rename(region = "left hemisphere Smrithi regions",
new_region = "AHBA regions")
# Use left_join to map the new names based on the region variable
MRI_model3_leftHem_new_regionNames <- MRI_model3_leftHem %>%
left_join(standard_region_names, by = "region") %>% # Join based on the region variable
mutate(region = ifelse(!is.na(new_region), new_region, region)) %>% # Replace region names with new ones
select(-new_region) # Remove the extra column if needed
Merging the AHBA normed values with Smrithi’s MRI data
AHBA_MRI_merged <- full_join(AHBA_normed_pivot_sigONLY, MRI_model3_leftHem_new_regionNames, by = "region", multiple = "all")
AHBA_MRI_merged_organized <- AHBA_MRI_merged %>%
select(-Genotype)
colnames(AHBA_MRI_merged_organized)[3] <- "AHBA_expression"
colnames(AHBA_MRI_merged_organized)[8] <- "t_value"
Exporting as csv AHBA_MRI_merged_organized
setwd("/Users/tammyray/Desktop/aaron_lab_2024/CSV_data_sheets")
write_csv(AHBA_MRI_merged_organized, "AHBA_MRI_merged.csv")
Pearson correlation analysis I want to do a correlation analysis
between the AHBA expression and the MRI data
Creating functions to compute correlation and p-value, created by
ChatGPT
correlation_with_pvalue_pearson <- function(x, y) {
test <- cor.test(x, y, method = "pearson")
return(data.frame(correlation = test$estimate, p_value = test$p.value))
}
correlation_with_pvalue_spearman <- function(x, y) {
test <- cor.test(x, y, method = "spearman")
return(data.frame(correlation = test$estimate, p_value = test$p.value))
}
Running the correlation analysis
# Group by gene_symbol and compute correlation between AHBA_expression and Estimate
cor_results_Estimate_pearson <- AHBA_MRI_merged_organized %>%
group_by(gene_symbol) %>%
summarize(correlation = cor(AHBA_expression, Estimate, method = "pearson"),
p_value = correlation_with_pvalue_pearson(AHBA_expression, Estimate)$p_value) %>%
mutate(in_16p_locus = ifelse(gene_symbol %in% sixteen_p_11.2_genes, "Yes", "No"))
#Trying a spearman correlation analysis instead
cor_results_Estimate_spearman <- AHBA_MRI_merged_organized %>%
group_by(gene_symbol) %>%
summarize(correlation = cor(AHBA_expression, Estimate, method = "spearman"),
p_value = cor.test(AHBA_expression, Estimate, method = "spearman")$p.value) %>%
mutate(in_16p_locus = ifelse(gene_symbol %in% sixteen_p_11.2_genes, "Yes", "No"))
# Doing the same thing for the t value
# Pearson correlation
cor_results_t_value_pearson <- AHBA_MRI_merged_organized %>%
group_by(gene_symbol) %>%
summarize(correlation = cor(AHBA_expression, t_value, method = "pearson"),
p_value = correlation_with_pvalue_pearson(AHBA_expression, t_value)$p_value) %>%
mutate(in_16p_locus = ifelse(gene_symbol %in% sixteen_p_11.2_genes, "Yes", "No"))
#Spearman correlation
cor_results_t_value_spearman <- AHBA_MRI_merged_organized %>%
group_by(gene_symbol) %>%
summarize(correlation = cor(AHBA_expression, t_value, method = "spearman"),
p_value = cor.test(AHBA_expression, t_value, method = "spearman")$p.value) %>%
mutate(in_16p_locus = ifelse(gene_symbol %in% sixteen_p_11.2_genes, "Yes", "No"))
Exporting the correlation analysis dataframes to CSV files
setwd("/Users/tammyray/Desktop/aaron_lab_2024/CSV_data_sheets")
write_csv(cor_results_Estimate_pearson, "AHBA_MRI_correlation_Estimate_Pearson.csv")
write_csv(cor_results_Estimate_spearman, "AHBA_MRI_correlation_Estimate_Spearman.csv")
write_csv(cor_results_t_value_pearson, "AHBA_MRI_correlation_t_value_Pearson.csv")
write_csv(cor_results_t_value_spearman, "AHBA_MRI_correlation_t_value_Spearman.csv")
Now, I want to visualize the correlation data
#Scatterplot showing relationship between p value and correlation, not super useful but educational for me!
ggplot(cor_results_t_value_spearman, aes(x=p_value, y=correlation, color=in_16p_locus)) +
geom_point() +
labs(title = "Spearman correlation of t-value",
x = "p value",
y = "correlation") +
theme_minimal() +
geom_vline(aes(xintercept = 0.05))

#making a density curve instead?
ggplot(cor_results_t_value_spearman, aes(x=correlation, color=in_16p_locus)) +
geom_density() +
labs(title = "Spearman correlation of t-value",
x = "Correlation Coefficient",
y = "Density") +
theme_minimal()

# making a histogram instead
ggplot(cor_results_t_value_spearman, aes(x= abs(correlation), fill=in_16p_locus)) +
geom_histogram(position = "identity", alpha = 0.6) +
labs(title = "Spearman correlation of t-value",
x = "Absolute Value of Correlation Coefficient",
y = "Frequency") +
theme_minimal() +
xlim(0, 0.6) + ylim(0, 8)
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Warning: Removed 4 rows containing missing values or values outside the scale range (`geom_bar()`).

ggplot(cor_results_Estimate_spearman, aes(x=abs(correlation), fill=in_16p_locus)) +
geom_histogram(position = "identity", alpha = 0.6) +
labs(title = "Spearman correlation of Estimate(~effect size)",
x = "Absolute Value of Correlation Coefficient",
y = "Frequency") +
theme_minimal() +
xlim(0, 0.6) + ylim(0, 8)
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Warning: Removed 4 rows containing missing values or values outside the scale range (`geom_bar()`).

Now I want to plot the data
library("ggpubr")
library(plotly)
Doing the above plotting for the 16p genes only
# Doing the above plotting for the NON 16p genes ----
AHBA_MRI_merged_organized_NOT_IN_16p_locus <- AHBA_MRI_merged_organized %>% filter(in_16p_region == "No")
scatter_plot_NOT_16p_genes <- ggplot(AHBA_MRI_merged_organized_NOT_IN_16p_locus, aes(x = AHBA_expression, y = Estimate, color = region)) +
geom_point(size = 0.1) +
geom_smooth(method = "lm", se = FALSE, color = "blue", linewidth = 0.5, fullrange = TRUE) + # Add a line of best fit (linear regression)
labs(title = "Scatter plots of AHBA Expression vs Estimate for Genes NOT in 16p locus",
x = "AHBA Expression",
y = "Estimate") +
facet_wrap(~ gene_symbol, scales = "free") + # Separate plots for each gene
theme_minimal() +
stat_cor(aes(label = paste(..r.label.., sep = "~`,`~")),
method = "pearson", label.x = 3, label.y = 0) + # Add correlation coefficients to the plot
xlim(0, 1) # Adjust axis limits
# Convert to a plotly object
interactive_plot_NOT_16p_genes <- ggplotly(scatter_plot_NOT_16p_genes, tooltip = c("text"))
# Display the interactive plot
interactive_plot_NOT_16p_genes
Adding correlation coefficiencies and p values to plots 1. Making new
dataframw with facet labels
# Merge main data with correlation results
plot_data_t_value_spearman <- AHBA_MRI_merged_organized %>%
left_join(cor_results_t_value_spearman, by = "gene_symbol") %>% # Merge by gene_symbol
mutate(facet_label = paste0(gene_symbol, "\n",
"| R: ", round(correlation, 2),
", p: ", round(p_value, 3)))
- replotting data
ggplot(plot_data_t_value_spearman, aes(x = AHBA_expression, y = t_value, color = region)) +
geom_point(size = 0.1) +
geom_smooth(method = "lm", se = FALSE, color = "blue", linewidth = 0.5, fullrange = TRUE) + # Add a line of best fit (linear regression)
labs(title = "Scatter plots of AHBA Expression vs t-value for all Genes",
x = "AHBA Expression",
y = "t-value") +
facet_wrap(~ facet_label, scales = "free") + # Use the custom facet label
theme_minimal() +
xlim(0, 1) #+ ylim(-0.7, 0.7) # Adjust axis limits
LS0tCnRpdGxlOiAiMTZwMTEuMiBDTlYgcHJvamVjdCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIFdoZW4geW91IGV4ZWN1dGUgY29kZSB3aXRoaW4gdGhlIG5vdGVib29rLCB0aGUgcmVzdWx0cyBhcHBlYXIgYmVuZWF0aCB0aGUgY29kZS4gCgpUcnkgZXhlY3V0aW5nIHRoaXMgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpSdW4qIGJ1dHRvbiB3aXRoaW4gdGhlIGNodW5rIG9yIGJ5IHBsYWNpbmcgeW91ciBjdXJzb3IgaW5zaWRlIGl0IGFuZCBwcmVzc2luZyAqQ21kK1NoaWZ0K0VudGVyKi4gCgpBZGQgYSBuZXcgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpJbnNlcnQgQ2h1bmsqIGJ1dHRvbiBvbiB0aGUgdG9vbGJhciBvciBieSBwcmVzc2luZyAqQ21kK09wdGlvbitJKi4KCldoZW4geW91IHNhdmUgdGhlIG5vdGVib29rLCBhbiBIVE1MIGZpbGUgY29udGFpbmluZyB0aGUgY29kZSBhbmQgb3V0cHV0IHdpbGwgYmUgc2F2ZWQgYWxvbmdzaWRlIGl0IChjbGljayB0aGUgKlByZXZpZXcqIGJ1dHRvbiBvciBwcmVzcyAqQ21kK1NoaWZ0K0sqIHRvIHByZXZpZXcgdGhlIEhUTUwgZmlsZSkuIAoKVGhlIHByZXZpZXcgc2hvd3MgeW91IGEgcmVuZGVyZWQgSFRNTCBjb3B5IG9mIHRoZSBjb250ZW50cyBvZiB0aGUgZWRpdG9yLiBDb25zZXF1ZW50bHksIHVubGlrZSAqS25pdCosICpQcmV2aWV3KiBkb2VzIG5vdCBydW4gYW55IFIgY29kZSBjaHVua3MuIEluc3RlYWQsIHRoZSBvdXRwdXQgb2YgdGhlIGNodW5rIHdoZW4gaXQgd2FzIGxhc3QgcnVuIGluIHRoZSBlZGl0b3IgaXMgZGlzcGxheWVkLgoKSW1wb3J0IG5lY2Vzc2FyeSBsaWJyYXJpZXMKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQoKCmBgYAoKSW1wb3J0aW5nIG5lY2VzYXJ5IENTViBmaWxlcwpgYGB7cn0KI1NldHRpbmcgd29ya2luZyBkaXJlY3RvcnkKc2V0d2QoIi9Vc2Vycy90YW1teXJheS9EZXNrdG9wL0Fhcm9uXzE2cF9JbWFnaW5nX1RyYW5zY3JpcHRvbWljcy9DU1ZfZGF0YV9zaGVldHMvdHJhbnNjcmlwdG9taWNfZGF0YXNoZWV0cyIpCiNJbXBvcnRpbmcgdHJhbmNyaXB0b21pYyBkYXRhc2RldHMKVGFsa293c2tpMjAxNCA8LSByZWFkLmNzdigiVGFsa293c2tpXzIwMTRfVGFibGVTM19IdW1hbl9EZWwuY3N2IikKVXJyZXN0aTIwMjFfM01fb3JnYW5vaWQgPC0gcmVhZC5jc3YoIlVycmVzdGktMjAyMV9ERUctM00tY29ydGljYWwtb3JnYW5vaWQuY3N2IikKUm90aDIwMjAgPC0gIHJlYWQuY3N2KCJSb3RoXzIwMjBfREVHLWhJUFNDLW5ldXJhbC1lbmRvZGVybU1lc29kZXJtLmNzdiIpCiNJbXBvcnRpbmcgZmlsZSBjb250YWluaW5nIDE2cDExLjIgZ2VuZSBsaXN0CmNocjE2cDExLjJfZ2VuZV9saXN0X0t1c2VuZGEyMDE1IDwtICByZWFkLmNzdigiS3VzZW5kYV8yMDE1X1RhYmxlUzFfMTZwMTEuMl9nZW5lX2xpc3QuY3N2IikKI0NyZWF0aW5nIGEgdmVjdG9yIG9mIGFsbCBnZW5lcyBpbiB0aGUgMTZwMTEuMiBjaHJvbW9zb21hbCByZWdpb24Kc2l4dGVlblAxMS4yX2dlbmVzIDwtIGNocjE2cDExLjJfZ2VuZV9saXN0X0t1c2VuZGEyMDE1JEdlbmUuc3ltYm9sCgpgYGAKCk1vZGlmeWluZyBkYXRhZnJhbWVzLCBzdWNoIHRoYXQgdGhleSBoYXZlIHRoZSBzYW1lIGNvbHVtbiBuYW1lcywgaW4gb3JkZXIgdG8gY29tYmluZSB0aGVtCgoxLiBVcmVzdGkgMjAyMSBjb3J0aWNhbCBvcmdhbm9pZHMgZGF0YQpgYGB7cn0KVXJyZXN0aTIwMjFfM01fb3JnYW5vaWRfdGlkeSA8LSBVcnJlc3RpMjAyMV8zTV9vcmdhbm9pZCAlPiUKICAjcmVtb3ZlIGNvbHVtbnMgdGhhdCBpIGRvIG5vdCBuZWVkCiAgc2VsZWN0KC1jKCJHZW5lLkJpb3R5cGUiLCAibG9nMi5GQy4uRFVQLnZzLkRFTCIsICJQLnZhbHVlLi5EVVAudnMuREVMIiwgIkZEUi5hZGp1c3RlZC5QLnZhbHVlLi5EVVAudnMuREVMIiwgImxvZzIuRkMuLkRVUC52cy5DVEwiLAogICAgICAgICAgICAiUC52YWx1ZS4uRFVQLnZzLkNUTCIsICJGRFIuYWRqdXN0ZWQuUC52YWx1ZS4uRFVQLnZzLkNUTCIsICJGRFIuYWRqdXN0ZWQuUC52YWx1ZS4uREVMLnZzLkNUTCIpKSAlPiUKICAjcmVuYW1lIGNvbHVtbnMgdG8gdGhlIHN0YW5kYXJkaXplZCBuYW1lcyBJIGRlY2lkZWQgb24KICByZW5hbWUoImdlbmVfbmFtZSIgPSAiSEdOQy5TeW1ib2wiLAogICAgICAgICAibG9nMl9mb2xkX2NoYW5nZSIgPSAibG9nMi5GQy4uREVMLnZzLkNUTCIsCiAgICAgICAgICJwX3ZhbHVlIiA9ICJQLnZhbHVlLi5ERUwudnMuQ1RMIiwKICAgICAgICAgImdlbmVfZGVzY3JpcHRpb24iID0gIkRlc2NyaXB0aW9uIiwgCiAgICAgICAgICJFTlNFTUJMX0lEIiA9ICJFTlNFTUJMLklEIikgJT4lCiAgI2FkZCBhIGNvbHVtbiBmb3IgdGhlIGRhdGEgc291cmNlCiAgbXV0YXRlKCAic2FtcGxlX3R5cGUiID0gImNvcnRpY2FsIG9yZ2Fub2lkIiwgImRhdGFfc291cmNlIiA9ICJVcnJlc3RpIGV0IGFsLiAyMDIxIiwgIlByZXNlbnQuaW4udGhlLjE2cDExLjIuUmVnaW9uIiA9ICIiKSAlPiUKICAjcmVvcmRlciBjb2x1bW5zIHNvIHRoYXQgdGhlIGVuc2VtYmxlX0lEIGNvbHVtbiwgd2hpY2ggbm90IGFsbCBkYXRhZnJhbWVzIHdpbGwgaGF2ZSwgaXMgYXQgdGhlIGVuZAogIHJlbG9jYXRlKCJFTlNFTUJMX0lEIiwgLmFmdGVyID0gImRhdGFfc291cmNlIikKCmBgYAoKMi4gUm90aCAyMDIwIGRhdGEKYGBge3J9ClJvdGgyMDIwX3RpZHkgPC0gUm90aDIwMjAgJT4lCiAgIyByZW1vdmUgY29sdW1ucyB0aGF0IEkgZG8gbm90IG5lZWQKICBzZWxlY3QoLWMoIlNGQVJJLkdlbmUuU2NvcmUiLCAiU0ZBUkkuR2VuZS5TY29yZS5DYXRlZ29yeSIsICJodHRwcy4uLmdlbmUuc2Zhcmkub3JnLmFib3V0LmdlbmUuc2NvcmluZy5jcml0ZXJpYS4iKSkgJT4lCiAgI3JlbmFtZSBjb2x1bW5zIHRvIHRoZSBzdGFuZGFyZGl6ZWQgbmFtZXMgSSBkZWNpZGVkIG9uCiAgcmVuYW1lKCJnZW5lX25hbWUiID0gIlgxNnAxMS4yLkRFLkdlbmVzIiwKICAgICAgICAgImxvZzJfZm9sZF9jaGFuZ2UiID0gIkxvZzIuRm9sZC5DaGFuZ2UuLlBvc2l0aXZlLnZhbHVlcy5hcmUudXByZWd1bGF0ZWQuaW4uREVMLiIsCiAgICAgICAgICJwX3ZhbHVlIiA9ICJBZGp1c3RlZC5QLlZhbHVlIikgJT4lCiAgI2FkZCBjb2x1bW5zIGZvciB0aGUgZGF0YSBzb3VyY2UsIHNhbXBsZSB0eXBlLCBhbmQgZXh0cmFzIHRvIG1hdGNoIHRoZSBhYm92ZSBkYXRhc2V0CiAgbXV0YXRlKCJnZW5lX2Rlc2NyaXB0aW9uIiA9ICIiLCAic2FtcGxlX3R5cGUiID0gImhJUFNDIiwgImRhdGFfc291cmNlIiA9ICJSb3RoIGV0IGFsLiAyMDIwIiwgIkVOU0VNQkxfSUQiID0gIiIpICU+JQogICNyZW9yZGVyIGNvbHVtbnMgdG8gbWF0Y2ggdGhlIG90aGVyIGRhdGFmcmFtZXMKICByZWxvY2F0ZSgiZ2VuZV9kZXNjcmlwdGlvbiIsIC5hZnRlciA9ICJnZW5lX25hbWUiKSAlPiUKICByZWxvY2F0ZSgiUHJlc2VudC5pbi50aGUuMTZwMTEuMi5SZWdpb24iLCAuYWZ0ZXIgPSAiRU5TRU1CTF9JRCIpCgpgYGAKCjMuIFRhbGtvd3NraSAyMDE0IGRhdGEKYGBge3J9IApUYWxrb3dza2kyMDE0X3RpZHkgPC0gVGFsa293c2tpMjAxNCAlPiUgCiAgc2VsZWN0KC1jKCJHZW5lSW5mbyIsICJDaHIiLCAiU3RhcnQiLCAiU3RvcCIpKSAlPiUKICAjc2VsZWN0KC1jKCJHZW5lSW5mbyIsICJDaHIiLCAiU3RhcnQiLCAiU3RvcCIpKSAlPiUKICAjVHJhbnNmb3JtaW5nIHRoZSBmb2xkY2hhbmdlIHRvIGxvZzIgZm9sZGNoYW5nZQogIG11dGF0ZSgiRm9sZENoYW5nZSIgPSBsb2cyKEZvbGRDaGFuZ2UpKSAlPiUKICAjcmVuYW1lIGNvbHVtbnMgdG8gdGhlIHN0YW5kYXJkaXplZCBuYW1lcyBJIGRlY2lkZWQgb24KICByZW5hbWUoImdlbmVfbmFtZSIgPSAiR2VuZUlEIiwKICAgICAgICAgImxvZzJfZm9sZF9jaGFuZ2UiID0gIkZvbGRDaGFuZ2UiLAogICAgICAgICAicF92YWx1ZSIgPSAicGVybVB2YWxfRGVsIikgJT4lCiAgI2FkZCBjb2x1bW5zIGZvciB0aGUgZGF0YSBzb3VyY2UsIHNhbXBsZSB0eXBlLCBhbmQgZXh0cmFzIHRvIG1hdGNoIHRoZSBhYm92ZSBkYXRhc2V0CiAgbXV0YXRlKCJnZW5lX2Rlc2NyaXB0aW9uIiA9ICIiLCAic2FtcGxlX3R5cGUiID0gImhMQ0wiLCAiZGF0YV9zb3VyY2UiID0gIlRhbGtvd3NraSBldCBhbC4gMjAxNCIsICJFTlNFTUJMX0lEIiA9ICIiLCAiUHJlc2VudC5pbi50aGUuMTZwMTEuMi5SZWdpb24iID0gIiIpICU+JQogICNyZW9yZGVyIGNvbHVtbnMgdG8gbWF0Y2ggdGhlIG90aGVyIGRhdGFmcmFtZXMKICByZWxvY2F0ZSgiZ2VuZV9kZXNjcmlwdGlvbiIsIC5hZnRlciA9ICJnZW5lX25hbWUiKSAlPiUKICByZWxvY2F0ZSgicF92YWx1ZSIsIC5hZnRlciA9ICJsb2cyX2ZvbGRfY2hhbmdlIikKCmBgYAoKUG90ZW50aWFsIG5leHQgc3RlcDogSSB0cmllZCB0byBhZGQgaW4gdGhlIGVuc2VtYmwgSUQgZm9yIHRoZSBUYWxrb3dza2kgMjAxNCBkYXRhLCBidXQgdGhhdCBkYXRhc2V0IHVzZWQgYW4gb2xkIHJlZnJlbmNlIHRyYW5zY3JpcHRvbWUgYW5kIHNvLCB1c2luZyB0aGUgCmNocm9tb3NvbWFsIHN0YXJ0IGFuZCBzdG9wIHBvc2l0aW9ucyBhbmQgY2hyb21vc29tZSBudW1iZXIsIEkgd2FzIHVuYWJsZSB0byBmaW5kIHRoZSBlbnNlbWJsIElEIGZvciB0aGUgZ2VuZXMgaW4gdGhhdCBkYXRhc2V0LiBJCgoKCgpOb3csIEkgd2FudCB0byBmaWxsIGluIHRoZSAiUHJlc2VudC5pbi50aGUuMTZwMTEuMi5SZWdpb24iIGNvbHVtbiBmb3IgdGhlIERFR19hbGxfdGltZXBvaW50c19vcmdhbm9pZF9VcnJlc3RpMjAyMV9tb2RpZmllZF9jb2x1bW5zIGRhdGFmcmFtZS4gCmBgYHtyfQojIFRoZSB2ZWN0b3Igc2l4dGVlblAxMS4yX2dlbmVzIGlzIGEgdmVjdG9yIGNvbnRhaW5pbmcgYWxsIGdlbmVzIGxvY2F0ZWQgaW4gdGhlIDE2cDExLjIgY2hyb21vc29tYWwgcmVnaW9uCiMgSSB3YW50IHRvIGNoYW5nZSB0aGUgdmFsdWUgb2YgdGhlICJQcmVzZW50LmluLnRoZS4xNnAxMS4yLlJlZ2lvbiIgY29sdW1uIHRvICJZZXMiIGlmIHRoZSBnZW5lIG5hbWUgaXMgaW4gdGhlIHZlY3RvciwgYW5kICJObyIgaWYgaXQgaXMgbm90CgpVcnJlc3RpMjAyMV8zTV9vcmdhbm9pZF90aWR5JFByZXNlbnQuaW4udGhlLjE2cDExLjIuUmVnaW9uIDwtCiAgaWZlbHNlKFVycmVzdGkyMDIxXzNNX29yZ2Fub2lkX3RpZHkkZ2VuZV9uYW1lICVpbiUgc2l4dGVlblAxMS4yX2dlbmVzLCAiWWVzIiwgIk5vIikKUm90aDIwMjBfdGlkeSRQcmVzZW50LmluLnRoZS4xNnAxMS4yLlJlZ2lvbiA8LQogIGlmZWxzZShSb3RoMjAyMF90aWR5JGdlbmVfbmFtZSAlaW4lIHNpeHRlZW5QMTEuMl9nZW5lcywgIlllcyIsICJObyIpClRhbGtvd3NraTIwMTRfdGlkeSRQcmVzZW50LmluLnRoZS4xNnAxMS4yLlJlZ2lvbiA8LQogIGlmZWxzZShUYWxrb3dza2kyMDE0X3RpZHkkZ2VuZV9uYW1lICVpbiUgc2l4dGVlblAxMS4yX2dlbmVzLCAiWWVzIiwgIk5vIikKCmBgYAoKCk5vdyBJIGNvbWJpbmUgYWxsIDMgb3JnYW5pemVkIGRhdGFmcmFtZXMgaW50byAxIGRhdGFmcmFtZQpgYGB7cn0KYWxsX0RFR19kYXRhIDwtIHJiaW5kKFVycmVzdGkyMDIxXzNNX29yZ2Fub2lkX3RpZHksIFJvdGgyMDIwX3RpZHksIFRhbGtvd3NraTIwMTRfdGlkeSkKCiMgTm93LCBJIHdhbnQgdG8gbG9vayBhdCB0aGUgZ2VuZXMgaW4gdGhlIDE2cDExLjIgcmVnaW9uIG9ubHksIGZyb20gdGhlIGFsbCBERUcgZGF0YS4gU28gSSB3aWxsIGZpbHRlciB0aGUgYWxsX0RFR19kYXRhIGRhdGFmcmFtZSB0byBvbmx5IGluY2x1ZGUgdGhvc2UgZ2VuZXMKYWxsX0RFR18xNnBfZ2VuZXMgPC0gYWxsX0RFR19kYXRhICU+JQogIGZpbHRlcihQcmVzZW50LmluLnRoZS4xNnAxMS4yLlJlZ2lvbiA9PSAiWWVzIikKCmBgYAoKCk5vIEkgd2lsbCBkbyBhIG1ldGFhbmFseXNpcyB0byBjb21iaW5lIGV2ZXJ5IGluc3RhbmNlIG9mIGEgZ2VuZSBpbnRvIG9uZSByb3csIHNvIHRoYXQgSSBjYW4gc2VlIGFsbCB0aGUgZGF0YSBmb3IgZWFjaCBnZW5lIGluIG9uZSByb3cKTG9nIGZvbGQgY2hhbmdlIGlzIHdlaWdodGVkIGJ5IHAtdmFsdWUKcCB2YWx1ZXMgYXJlIGNvbWJpbmVkIHdpdGggZmlzaGVycyBleGFjdCB0ZXN0CmBgYHtyfQptZXRhX2FuYWx5c2lzX2FsbF9ERUdfZGF0YSA8LSBhbGxfREVHX2RhdGEgJT4lCiAgZ3JvdXBfYnkoZ2VuZV9uYW1lKSAlPiUKICBzdW1tYXJpemUoY29tYmluZWRfbG9nMl9mb2xkX2NoYW5nZSA9IHN1bShsb2cyX2ZvbGRfY2hhbmdlIC8gKHBfdmFsdWUgKyAxZS04KSkgLyBzdW0oMSAvIChwX3ZhbHVlICsgMWUtOCkpLCAgIyBXZWlnaHRlZCBsb2dGQyB1c2luZyBwLXZhbHVlcy4KICAgICAgICAgICAgIyBBIHNtYWxsIGNvbnN0YW50ICgxZS04KSBpcyBhZGRlZCB0byBhdm9pZCBkaXZpc2lvbiBieSB6ZXJvIGlmIHRoZXJlIGFyZSB2ZXJ5IHNtYWxsIHAtdmFsdWVzLgogICAgICAgICAgICAjaW4gdGhlIG5leHQgbGluZSBvZiBjb2RlIEkgd2lsbCBkbyBhIGZpc2hlciB0ZXN0IHRvIGNvbWJpbmUgdGhlIHAtdmFsdWVzCiAgICAgICAgICAgIGNvbWJpbmVkX3BfdmFsdWUgPSAxIC0gcGNoaXNxKHN1bShxY2hpc3EoMSAtIHBfdmFsdWUsIDEsIGxvd2VyLnRhaWwgPSBGQUxTRSkpLCBsZW5ndGgocF92YWx1ZSksIGxvd2VyLnRhaWwgPSBGQUxTRSkpICU+JQogICN0aGUgYWJvdmUgY29kZSB3aWxsIHJldHVybiBhIGRhdGFmcmFtZSB0aGF0IG9ubHkgY29udGFpbnMgMyBvZiB0aGUgY29sdW1ucy4gSW4gdGhlIG5leHQgbGluZSBvZiBjb2RlIEkgd2lsbCBicmluZyB0aGUgcmVzdCBvZiB0aGUgY29sdW1ucyBiYWNrIHRvIHRoaXMgbmV3IGRhdGFmcmFtZQogIGxlZnRfam9pbihhbGxfREVHX2RhdGEsIGJ5ID0gImdlbmVfbmFtZSIpCgoKI0tlZXAgdHJhY2sgb2YgaWYgdGhlIGdlbmUgY29tYmluZWQgbG9nZm9sZGNhaG5nZSBhbmQgcC12YWx1ZSBhcmUgZnJvbSBtdWx0aXBsZSBkYXRhIHNvdXJjZXMKbWV0YV9hbmFseXNpc19hbGxfREVHX2RhdGEkbXVsdGlwbGVfZGF0YV9zb3VyY2VzIDwtIGlmZWxzZShkdXBsaWNhdGVkKG1ldGFfYW5hbHlzaXNfYWxsX0RFR19kYXRhJGdlbmVfbmFtZSkgfCBkdXBsaWNhdGVkKG1ldGFfYW5hbHlzaXNfYWxsX0RFR19kYXRhJGdlbmVfbmFtZSwgZnJvbUxhc3QgPSBUUlVFKSwgIlllcyIsICJObyIpCgoKI05vdywgSSB3YW50IHRvIGRlbGV0ZSByb3dzIHRoYXQgaGF2ZSB0aGUgc2FtZSBnZW5lIG5hbWUgYW5kIHJlbW92ZSB0aGUgY29sdW1ucyB0aGF0IGhhdmUgdGhlIG9yaWdpbmFsIGxvZzJfZm9sZF9jaGFuZ2UsIHBfdmFsdWUsIHNhbXBsZV90eXBlLCBhbmQgZGF0YV9zb3VyY2UKbWV0YV9hbmFseXNpc19hbGxfREVHX2RhdGEgPC0gbWV0YV9hbmFseXNpc19hbGxfREVHX2RhdGEgJT4lCiAgZGlzdGluY3QoZ2VuZV9uYW1lLCAua2VlcF9hbGwgPSBUUlVFKSAlPiUKICBzZWxlY3QoLWMobG9nMl9mb2xkX2NoYW5nZSwgcF92YWx1ZSwgc2FtcGxlX3R5cGUsIGRhdGFfc291cmNlKSkKCiNUaGlzIGNvZGUgYWRkcyBhIGNvbHVtbiBjYWxsZWQgc2lnbmlmaWNhbmNlIHRoYXQgd2lsbCBpbmRpY2F0ZSB0aGUgZGVncmVlIG9mIHNpZ25pZmljYW5jZSwganVzdCBsaWtlIFNtcml0aGkncyBjb2RlCm1ldGFfYW5hbHlzaXNfYWxsX0RFR19kYXRhIDwtIG1ldGFfYW5hbHlzaXNfYWxsX0RFR19kYXRhICU+JQogIG11dGF0ZSgic2lnbmlmaWNhbmNlIiA9IGNhc2Vfd2hlbigKICAgIGNvbWJpbmVkX3BfdmFsdWUgPCAwLjAwMSB+ICIqKioiLAogICAgY29tYmluZWRfcF92YWx1ZSA8IDAuMDEgfiAiKioiLAogICAgY29tYmluZWRfcF92YWx1ZSA8IDAuMDUgfiAiKiIsCiAgICBUUlVFIH4gIiAiCiAgKSkKCiNOb3cgaSB3aWxsIGNyZWF0ZSBhIG5ldyBkYXRhZnJhbWUgd2l0aCBvbmx5IHRoZSBnZW5lcyB0aGF0IGFyZSBzaWduaWZpY2FudGx5IGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBhdCBjb21iaW5lZCBwLXZhbHVlIDwgMC4wMDEKc2lnX2dlbmVzX3AwLjAwMV9ERUdfZGF0YSA8LSBtZXRhX2FuYWx5c2lzX2FsbF9ERUdfZGF0YSAlPiUKICBmaWx0ZXIoc2lnbmlmaWNhbmNlID09ICIqKioiKQoKYGBgCgpFeHBvcnRpbmcgdGhlIGRhdGFmcmFtZXMgdG8gQ1NWIGZpbGVzLCBpZiBkZXNpcmVkCgpgYGB7cn0Kc2V0d2QoIi9Vc2Vycy90YW1teXJheS9EZXNrdG9wL2Fhcm9uX2xhYl8yMDI0L291dHB1dCIpCgp3cml0ZS5jc3YoVXJyZXN0aTIwMjFfM01fb3JnYW5vaWRfdGlkeSwgZmlsZT0iVXJyZXN0aTIwMjFfM01fb3JnYW5vaWRfdGlkeS5jc3YiKQp3cml0ZS5jc3YoUm90aDIwMjBfdGlkeSwgZmlsZT0iUm90aDIwMjBfdGlkeS5jc3YiKQp3cml0ZS5jc3YoVGFsa293c2tpMjAxNF90aWR5LCBmaWxlPSJUYWxrb3dza2kyMDE0X3RpZHkuY3N2IikKd3JpdGUuY3N2KGFsbF9ERUdfZGF0YSwgZmlsZT0iYWxsX0RFR19kYXRhLmNzdiIpCndyaXRlLmNzdihtZXRhX2FuYWx5c2lzX2FsbF9ERUdfZGF0YSwgZmlsZT0ibWV0YV9hbmFseXNpc19hbGxfREVHX2RhdGEuY3N2IikKd3JpdGUuY3N2KHNpZ19nZW5lc19wMC4wMDFfREVHX2RhdGEsIGZpbGU9InNpZ19nZW5lc19wMC4wMDFfREVHX2RhdGEuY3N2IikKYGBgCgoKR2VuZSBvbnRvbG9neSBhbmFseXNpcwpJIGFtIHVzaW5nIGdwcm9maWxlcjIgdG8gZG8gbXkgR08gYW5hbHlzaXMKTG9hZGluZyBncHJvZmlsZXIyIHBhY2thZ2UKYGBge3J9CmxpYnJhcnkoZ3Byb2ZpbGVyMikKYGBgCgoKRG9pbmcgR08gYW5hbHlzaXMKYGBge3J9CiMgTWFraW5nIHZlY3RvciBvZiBnZW5lcyBpbiBzaWcgZ2VuZSBkYXRhZnJhbWUKZXhwX2dlbmVfbGlzdF8xX3BfMC4wMDEgPC0gc2lnX2dlbmVzX3AwLjAwMV9ERUdfZGF0YSRnZW5lX25hbWUKCiMgdXNpbmcgZ29zdCBmdW5jdGlvbiBmcm1vIGdwcm9maWxlcjIgdG8gZG8gR08gYW5hbHlzaXMKR09fcmVzdWx0c19leHBfZ2VuZV9saXN0X3AwLjAwMSA9IGdvc3QocXVlcnkgPSBleHBfZ2VuZV9saXN0XzFfcF8wLjAwMSwKICAgICAgICAgICAgICAgb3JnYW5pc20gPSAiaHNhcGllbnMiLAogICAgICAgICAgICAgICBjb3JyZWN0aW9uX21ldGhvZCA9ICJmZHIiKQpHT19hbGxfcmVzdWx0c19wMC4wMDEgPC0gR09fcmVzdWx0c19leHBfZ2VuZV9saXN0X3AwLjAwMSRyZXN1bHQgJT4lCiAgc2VsZWN0KC1wYXJlbnRzKQoKI3B1dHRpbmcgbWV0YWRhdGEgZnJvbSBHTyBhbmFseXNpcyBpbnRvIGEgZGF0YWZyYW1lCkdPX21ldGFfcDAuMDAxIDwtIEdPX3Jlc3VsdHNfZXhwX2dlbmVfbGlzdF9wMC4wMDEkbWV0YQoKCiNDcmVhdGluZyBnZW5lIGxpc3RzIGZvciB1cHJlZ3VsYXRlZCBhbmQgZG93bnJlZ3VsYXRlZCBnZW5lcwpVUHJlZ3VsYXRlZF9zaWdfZ2VuZXNfcDAuMDAxX0RFR19kYXRhIDwtIHNpZ19nZW5lc19wMC4wMDFfREVHX2RhdGEgJT4lCiAgZmlsdGVyKGNvbWJpbmVkX2xvZzJfZm9sZF9jaGFuZ2UgPiAwKQpVUHJlZ3VsYXRlZF9leHBfZ2VuZV9saXN0XzFfcF8wLjAwMSA8LSBVUHJlZ3VsYXRlZF9zaWdfZ2VuZXNfcDAuMDAxX0RFR19kYXRhJGdlbmVfbmFtZQoKRE9XTnJlZ3VsYXRlZF9zaWdfZ2VuZXNfcDAuMDAxX0RFR19kYXRhIDwtIHNpZ19nZW5lc19wMC4wMDFfREVHX2RhdGEgJT4lCiAgZmlsdGVyKGNvbWJpbmVkX2xvZzJfZm9sZF9jaGFuZ2UgPCAwKQpET1dOcmVndWxhdGVkX3NpZ19nZW5lc19wMC4wMDFfREVHX2RhdGEgPC0gRE9XTnJlZ3VsYXRlZF9zaWdfZ2VuZXNfcDAuMDAxX0RFR19kYXRhJGdlbmVfbmFtZQoKdXBfcmVnX2dlbmVzIDwtIHNpZ19nZW5lc19wMC4wMDFfREVHX2RhdGEgJT4lIGZpbHRlcihjb21iaW5lZF9sb2cyX2ZvbGRfY2hhbmdlID4gMCkKdXBfcmVnX2dlbmVfbmFtZXMgPC0gdXBfcmVnX2dlbmVzJGdlbmVfbmFtZQoKIyBHTyBhbmFseXNpcyBvZiB1cHJlZ3VsYXRlZCBhbmQgZG93bnJlZ3VsYXRlZCBnZW5lcwpnb3N0cmVzX1VQcmVndWxhdGVkIDwtIGdvc3QocXVlcnkgPSBVUHJlZ3VsYXRlZF9leHBfZ2VuZV9saXN0XzFfcF8wLjAwMSwKICAgICAgICAgICAgICAgb3JnYW5pc20gPSAiaHNhcGllbnMiLAogICAgICAgICAgICAgICBjb3JyZWN0aW9uX21ldGhvZCA9ICJmZHIiKQoKZ29zdHJlc19VUHJlZ3VsYXRlZCA8LSBnb3N0cmVzX1VQcmVndWxhdGVkJHJlc3VsdAoKCmdvc3RyZXNfRE9XTnJlZ3VsYXRlZCA8LSBnb3N0KHF1ZXJ5ID0gRE9XTnJlZ3VsYXRlZF9zaWdfZ2VuZXNfcDAuMDAxX0RFR19kYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAiaHNhcGllbnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29ycmVjdGlvbl9tZXRob2QgPSAiZmRyIikKCmdvc3RyZXNfRE9XTnJlZ3VsYXRlZCA8LSBnb3N0cmVzX0RPV05yZWd1bGF0ZWQkcmVzdWx0CmBgYAoKRXhwb3J0aW5nIHRoZSBHTyBhbmFseXNpcyBkYXRhZnJhbWVzIHRvIENTViBmaWxlcywgaWYgZGVzaXJlZApgYGB7cn0Kc2V0d2QoIi9Vc2Vycy90YW1teXJheS9EZXNrdG9wL2Fhcm9uX2xhYl8yMDI0L291dHB1dCIpCndyaXRlLmNzdihnb3N0cmVzX3Jlc3VsdHMsIGZpbGU9Ii9Vc2Vycy90YW1teXJheS9EZXNrdG9wL0Fhcm9uXzE2cF9JbWFnaW5nX1RyYW5zY3JpcHRvbWljcy9vdXRwdXQvR09fMTZwMTEuMi1ERUdzX3AwLjAwMV9mZHItY29ycmVjdGlvbnMuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCgoKYGBgCgoKTk9XLCB3ZSBnZW5lcmF0ZSBtYXAgb2Ygb3VyIHNpZ25pZmljYW50IGdlbmVzIHRvIEFIQkEgc3BhdGlhbCBtYXAKCgpGaXJzdCwgcmVhZCBpbiB0aGUgZGF0YQpgYGB7cn0KQUhCQSA8LSByZWFkX3RzdigiL1VzZXJzL3RhbW15cmF5L0Rlc2t0b3AvQWFyb25fMTZwX0ltYWdpbmdfVHJhbnNjcmlwdG9taWNzL0NTVl9kYXRhX3NoZWV0cy9BbGxlbkhCQV9ES19FeHByZXNzaW9uTWF0cml4LnRzdiIpCiMgTm93LCBJIHdhbnQgdG8gY2NoYW5nZSB0aGUgY29sdW1uIGhlYWRlciBvZiB0aGUgZmlyc3QgY29sdW1uIG9mIHRoZSBBSEJBIGRhdGFmcmFtZSB0byBnZW5lX3N5bWJvbApjb2xuYW1lcyhBSEJBKVsxXSA8LSAiZ2VuZV9zeW1ib2wiCgpgYGAKCgpNYXBwaW5nIG91ciBzaWduaWZpY2FudCBnZW5lcyB0byB0aGUgQUhCQSBkYXRhc2V0CmBgYHtyfQojQ3JlYXRpbmcgdmVjdG9yIG9mIGdlbmUgbmFtZXMgaW4gb3VyIGV4cGVyaW1lbnRhbCBncm91cHMKc2lnX2dlbmVzX3AwLjAwMV9ERUdfZGF0YSAjZGF0YWZyYW1lIGNvbnRhaW5pbmcgYWxsIHNpZ25pZmljYW50IGdlbmVzCnNpZ19nZW5lX2xpc3QgPC0gc2lnX2dlbmVzX3AwLjAwMV9ERUdfZGF0YSRnZW5lX25hbWUgI3ZlY3RvciBvZiBhbGwgc2lnbmlmaWNhbnQgZ2VuZXMgbmFtZXMKc2l4dGVlblAxMS4yX2dlbmVzICNkYXRhZnJhbWUgY29udGFpbmluZyBhbGwgZ2VuZXMgaW4gMTZwMTEuMiBsb2N1cwpzaXh0ZWVuX3BfMTEuMl9nZW5lcyA8LSBjaHIxNnAxMS4yX2dlbmVfbGlzdF9LdXNlbmRhMjAxNSRHZW5lLnN5bWJvbCAjdmVjdG9yIG9mIGFsbCBnZW5lcyBpbiAxNnAgbG9jdXMKCkFIQkFfc2lnX2dlbmVzIDwtIEFIQkEgJT4lIGZpbHRlcihnZW5lX3N5bWJvbCAlaW4lIHNpZ19nZW5lX2xpc3QpCgojTk9URTogbm90IGFsbCBzaWcgZ2VuZXMgbWFwcGVkIHRvIEFIQkEgZGF0YXNldC4gSGVyZSBpcyBhIGxpc3Qgb2YgdGhlbSBzbyBJIGNhbiB0cm91Ymxlc2hvb3QgbGF0ZXIKZ2VuZXNfbm90X21hcHBlZCA8LSBzaWdfZ2VuZV9saXN0WyEoc2lnX2dlbmVfbGlzdCAlaW4lIEFIQkFfc2lnX2dlbmVzJGdlbmVfc3ltYm9sKV0KYGBgCk5PVEU6IE9ubHkgODcgb2YgdGhlIDEzMiBnZW5lcyBtYXBwZWQgdG8gdGhlIEFIQkEgZGF0YXNldAoKClRpZHlpbmcgdGhlIEFIQkEgc3Vic2V0IGRhdGFmcmFtZSB3aXRoIHNpZ25pZmljYW50IGdlbmVzIG9ubHkKYGBge3J9CkFIQkFfc2lnX2dlbmVzX3Bpdm90IDwtIEFIQkFfc2lnX2dlbmVzICU+JQogICNyZW1vdmUgdGhlICJBdmVyYWdlIGRvbm9yIGNvcnJlbGF0aW9uIHRvIHRoZSBtZWRpYW4iIGNvbHVtbgogIHNlbGVjdCgtIkF2ZXJhZ2UgZG9ub3IgY29ycmVsYXRpb24gdG8gbWVkaWFuIikgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtZ2VuZV9zeW1ib2wsIG5hbWVzX3RvID0gInJlZ2lvbiIsIHZhbHVlc190byA9ICJleHByZXNzaW9uIikgJT4lCiAgI2FkZGluZyBhIGNvbHVtbiBmb3IgaWYgZ2VuZSBpcyBpbiB0aGUgMTZwIHJlZ2lvbgogIG11dGF0ZShpbl8xNnBfcmVnaW9uID0gaWZlbHNlKGdlbmVfc3ltYm9sICVpbiUgc2l4dGVlbl9wXzExLjJfZ2VuZXMsICJZZXMiLCAiTm8iKSkgJT4lCiAgIyBBZGRpbmcgYSBjb2x1bW4gZm9yIGlmIGdlbmUgaXMgdXAgb3IgZG93bnJlZ3VsYXRlZAogIG11dGF0ZSh1cHJlZyA9IGlmZWxzZShnZW5lX3N5bWJvbCAlaW4lIHVwX3JlZ19nZW5lX25hbWVzLCAiWWVzIiwgIk5vIikpCgpgYGAKCgpHR3Bsb3QgdG8gdmlzdWFsaXplIHRoZSBkYXRhCmBgYHtyfQojIFZpc3VhbGl6aW5nIGV4cHJlc3Npb24gZGF0YSBvZiBzaWduaWZpY2FudCBnZW5lcwpnZ3Bsb3QoQUhCQV9zaWdfZ2VuZXNfcGl2b3QsIGFlcyh4PWV4cHJlc3Npb24sIHk9cmVnaW9uLCBzaGFwZT1pbl8xNnBfcmVnaW9uLCBjb2xvcj1nZW5lX3N5bWJvbCkpICsgCiAgZ2VvbV9wb2ludCgpICsgCiAgbGFicyh0aXRsZSA9ICJyZWdpb25hbCBleHByZXNzaW9uIG9mIHNpZ25pZmljYW50IGdlbmVzIGZyb20gMTZwIGRlbCBtZXRhLWFuYWx5c2lzIiwgeCA9ICJSYXcgRXhwcmVzc2lvbiIsIHkgPSAiQnJhaW4gUmVnaW9uIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgI0kgd2lsbCBtYWtlIHRoZSBsZWdlbmQgc21hbGxlciBhbmQgcHV0IGl0IHVuZGVybmVhdGggdGhlIGdyYXBoICBiZWNhdXNlIGl0IGlzIHRvbyBiaWcKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKwogIGd1aWRlcyhjb2xvcj0ibm9uZSIpCgojIHNhbWUgcGxvdCBidXQgYWVzdGhldGljcyBvbmx5IGZvciBnZW5lcyBpbiAxNnAgcmVnaW9uCmdncGxvdChBSEJBX3NpZ19nZW5lc19waXZvdCwgYWVzKHg9ZXhwcmVzc2lvbiwgeT1yZWdpb24sIGNvbG9yPWluXzE2cF9yZWdpb24pKSArIAogIGdlb21fcG9pbnQoKSArIAogIGxhYnModGl0bGUgPSAicmVnaW9uYWwgZXhwcmVzc2lvbiBvZiBzaWduaWZpY2FudCBnZW5lcyBmcm9tIDE2cCBkZWwgbWV0YS1hbmFseXNpcyIsIHggPSAiUmF3IEV4cHJlc3Npb24iLCB5ID0gIkJyYWluIFJlZ2lvbiIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogICNJIHdpbGwgbWFrZSB0aGUgbGVnZW5kIHNtYWxsZXIgYW5kIHB1dCBpdCB1bmRlcm5lYXRoIHRoZSBncmFwaCAgYmVjYXVzZSBpdCBpcyB0b28gYmlnCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpIAoKCmdncGxvdChBSEJBX3NpZ19nZW5lc19waXZvdCwgYWVzKHg9ZXhwcmVzc2lvbiwgeT1yZWdpb24sIGNvbG9yPXVwcmVnKSkgKyAKICBnZW9tX3BvaW50KCkgKyAKICBsYWJzKHRpdGxlID0gInJlZ2lvbmFsIGV4cHJlc3Npb24gb2Ygc2lnbmlmaWNhbnQgZ2VuZXMgZnJvbSAxNnAgZGVsIG1ldGEtYW5hbHlzaXMiLCB4ID0gIlJhdyBFeHByZXNzaW9uIiwgeSA9ICJCcmFpbiBSZWdpb24iKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICAjSSB3aWxsIG1ha2UgdGhlIGxlZ2VuZCBzbWFsbGVyIGFuZCBwdXQgaXQgdW5kZXJuZWF0aCB0aGUgZ3JhcGggIGJlY2F1c2UgaXQgaXMgdG9vIGJpZwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSAKYGBgCgoKTm93LCB3ZSB3YW50IHRvIHdvcmsgd2l0aCB0aGUgbm9ybWFsaXplZCBBSEJBIHZhbHVlcy4gVGhleSBhcmUgaW4gYSBtYXRsYWIgZmlsZSwgc28gZmlyc3QgSSB3aWxsIG5lZWQgdG8gY29udmVydCB0aGUgbWF0bGFiIGZpbGUgdG8gc29tZXRoaW5nIFIgY2FuIHJlYWQsIHdpdGggdGhlIFIubWF0bGFiIHBhY2thZ2UuIApOT1RFOiBUaGUgUi5tYXRsYWIgcGFja2FnZSBkb2VzIG5vdCBrZWVwIGNvbHVtbiBuYW1lcyBvZiB0aGUgb3JpZ2luYWwgZGF0YSB3aGVuIGNvbnZlcnRpbmcgdGhpbmdzLCBzbyBJIGhhZCB0byBhZGQgdGhlbSBiYWNrIGluLgoKRmlyc3QsIGxvYWQgbGlicmFyaWVzCmBgYHtyfQpsaWJyYXJ5KFIubWF0bGFiKQpgYGAKClNlY29uZCwgbG9hZCBpbiByZWxldmFudCBmaWxlcwpgYGB7cn0Kc2V0d2QoIi9Vc2Vycy90YW1teXJheS9EZXNrdG9wL0Fhcm9uXzE2cF9JbWFnaW5nX1RyYW5zY3JpcHRvbWljcyIpCkFIQkFfbm9ybWVkIDwtIHJlYWRNYXQoIlJPSXhHZW5lX2FwYXJjYXNlZ19JTlQubWF0IikKCnNldHdkKCIvVXNlcnMvdGFtbXlyYXkvRGVza3RvcC9BYXJvbl8xNnBfSW1hZ2luZ19UcmFuc2NyaXB0b21pY3MvQ1NWX2RhdGFfc2hlZXRzIikKcmVnaW9uX2FycmF5IDwtIHJlYWRfY3N2KCJSZWdpb25fbGFiZWxzX2Zvcl9hcGFyY2FzZWdfcGFyY2VsbGF0aW9uLmNzdiIsIGNvbF9uYW1lcyA9IEZBTFNFKQpgYGAKClRpZHlpbmcgdXAgdGhlIEFIQkFfbm9ybWVkIGRhdGFmcmFtZQpgYGB7cn0KQUhCQV9wYXJjZWxfZXhwcmVzc2lvbjAgPC0gYXMuZGF0YS5mcmFtZShBSEJBX25vcm1lZCRwYXJjZWxFeHByZXNzaW9uKQojIEdldHRpbmcgbGlzdCBvZiBnZW5lIG5hbWVzIAphcnJheV9nZW5lX25hbWVzIDwtIHVubGlzdChBSEJBX25vcm1lZCRwcm9iZUluZm9ybWF0aW9uW1syXV0pCiMgRmlyc3QgaSBuZWVkIHRvIGVkaXQgbXkgYXJyYXlfZ2VuZV9uYW1lcyB0byBhZGQgYSAwIGFzIHRoZSBmaXJzdCBpdGVtIGluIG15IGFycmF5CmFycmF5X2dlbmVfbmFtZXMgPC0gYygwLCBhcnJheV9nZW5lX25hbWVzKQojIE5vdywgSSB3YW50IHRvIHJlbmFtZSB0aGUgY29sdW1ucyBvZiB0aGUgQUhCQV9wYXJjZWxfZXhwcmVzc2lvbiBkYXRhZnJhbWUgdG8gdGhlIGdlbmUgbmFtZXMgaW4gYXJyYXlfZ2VuZV9uYW1lcwpjb2xuYW1lcyhBSEJBX3BhcmNlbF9leHByZXNzaW9uMCkgPC0gYXJyYXlfZ2VuZV9uYW1lcwoKI05vdywgSSB3YW50IHRvIGNoYW5nZSB0aGUgdmFsdWVzIG9mIGNvbHVtbiAxIG9mIHRoZSBBSEJBX3BhcmNlbF9leHByZXNzaW9uMCBkYXRhZnJhbWUgdG8gdGhlIHZhbHVlcyBpbiB0aGUgcmVnaW9uX2FycmF5IGRhdGFmcmFtZQojTWF5YmUgSSBqdXN0IG11dGF0ZSB0aGUgZGF0YWZyYW1lIHRvIGFkZCB0aGUgYXJyYXkgYXMgYSBjb2x1bW4sIG1vdmUgdGhhdCBjb2x1bW4gdG8gdGhlIGZyb250LCBhbmQgdGhlbiByZW1vdmUgdGhlIG9yaWdpbmFsIGNvbHVtbgpBSEJBX3BhcmNlbF9leHByZXNzaW9uMF9sYWJlbGVkIDwtIEFIQkFfcGFyY2VsX2V4cHJlc3Npb24wICU+JQogIG11dGF0ZShyZWdpb24gPSByZWdpb25fYXJyYXkpICU+JQogICNOb3cgaSB3YW50IHRvIG1vdmUgdGhlIHJlZ2lvbiR4MSB2YXIgdG8gYmUgdGhlIGZpcnN0IGNvbHVtbgogIHNlbGVjdChyZWdpb24sIGV2ZXJ5dGhpbmcoKSkgJT4lCiAgc2VsZWN0KC0iMCIpCgojWWF5IG5vdyBkYXRhIHRhYmxlIGlzIGFzIGkgd2FudCBpdCB0byBiZSEKIyBOb3cgSSB3aWxsIHBpdm90IHRoZSB0YWJsZSBzbyB0aGF0IGl0IG1hdGNoZXMgdGhlIEFIQkFfc2lnX2dlbmVzX2FsbF9waXZvdCB0YWJsZQpBSEJBX25vcm1lZF9waXZvdCA8LSBBSEJBX3BhcmNlbF9leHByZXNzaW9uMF9sYWJlbGVkICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gLXJlZ2lvbiwgbmFtZXNfdG8gPSAiZ2VuZV9zeW1ib2wiLCB2YWx1ZXNfdG8gPSAiZXhwcmVzc2lvbiIpICU+JQogIG11dGF0ZShpbl8xNnBfcmVnaW9uID0gaWZlbHNlKGdlbmVfc3ltYm9sICVpbiUgc2l4dGVlbl9wXzExLjJfZ2VuZXMsICJZZXMiLCAiTm8iKSkgJT4lCiAgdW5uZXN0KGNvbHMgPSByZWdpb24pCgoKCkFIQkFfbm9ybWVkX3Bpdm90X3NpZ09OTFkgPC0gQUhCQV9ub3JtZWRfcGl2b3QgJT4lCiAgZmlsdGVyKGdlbmVfc3ltYm9sICVpbiUgc2lnX2dlbmVfbGlzdCkKCgojIE5vdywgSSB3YW50IHRvIGNoYW5nZSB0aGUgY29sdW1uIG5hbWUgWDEgdG8gcmVnaW9uCmNvbG5hbWVzKEFIQkFfbm9ybWVkX3Bpdm90X3NpZ09OTFkpWzFdIDwtICJyZWdpb24iCgpgYGAKCkV4cG9ydGluZyBkYXRhZnJhbWVzIGFzIENTVnMKYGBge3J9CiMgT0ssIE5vdyB0aGF0IEkgaGF2ZSB0aGlzIGRhdGEsIEkgd2FudCB0byBwdXQgaXQgaW50byBhIENTViBzbyBJIGhhdmUgaXQgZm9yIGZ1dHVyZSByZWZlcmVuY2UKc2V0d2QoIi9Vc2Vycy90YW1teXJheS9EZXNrdG9wL2Fhcm9uX2xhYl8yMDI0L291dHB1dCIpCndyaXRlLmNzdihBSEJBX25vcm1lZF9waXZvdCwgIk5vcm1lZF9BSEJBX3NpZ19nZW5lcy5jc3YiKQp3cml0ZS5jc3YoQUhCQV9ub3JtZWRfcGl2b3Rfc2lnT05MWSwgIk5vcm1lZF9BSEJBX3NpZ19nZW5lc19PTkxZLmNzdiIpCndyaXRlLmNzdihBSEJBX3NpZ19nZW5lc19hbGxfcGl2b3RfT05MWSwgIlJhd19BSEJBX3NpZ19nZW5lc19PTkxZLmNzdiIpCmBgYAoKClBsb3R0aW5nIHRoZSBub3JtYWxpemVkIEFIQkEgZGF0YQpgYGB7cn0KZ2dwbG90KEFIQkFfbm9ybWVkX3Bpdm90X3NpZ09OTFksIGFlcyh4PWV4cHJlc3Npb24sIHk9cmVnaW9uLCBjb2xvcj1nZW5lX3N5bWJvbCkpICsgCiAgZ2VvbV9wb2ludCgpICsgCiAgbGFicyh0aXRsZSA9ICJOT1JNQUxJWkVEIHJlZ2lvbmFsIGV4cHJlc3Npb24gb2Ygc2lnbmlmaWNhbnQgZ2VuZXMgZnJvbSAxNnAgZGVsIG1ldGEtYW5hbHlzaXMiLCB4ID0gIk5vcm1hbGl6ZWQgRXhwcmVzc2lvbiIsIHkgPSAiQnJhaW4gUmVnaW9uIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgI0kgd2lsbCByZW1vdmUgdGhlIGxlZ2VuZCBiZWNhdXNlIGl0IGlzIHRvbyBiaWcKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgoKIyBWaXN1YWxpemluZyBleHByZXNzaW9uIGRhdGEgb2Ygc2lnbmlmaWNhbnQgZ2VuZXMKZ2dwbG90KEFIQkFfbm9ybWVkX3Bpdm90X3NpZ09OTFksIGFlcyh4PWV4cHJlc3Npb24sIHk9cmVnaW9uLCBzaGFwZT1pbl8xNnBfcmVnaW9uLCBjb2xvcj1nZW5lX3N5bWJvbCkpICsgCiAgZ2VvbV9wb2ludCgpICsgCiAgbGFicyh0aXRsZSA9ICJOT1JNQUxJWkVEIHJlZ2lvbmFsIGV4cHJlc3Npb24gb2Ygc2lnbmlmaWNhbnQgZ2VuZXMgZnJvbSAxNnAgZGVsIG1ldGEtYW5hbHlzaXMiLCB4ID0gIk5vcm1hbGl6ZWQgRXhwcmVzc2lvbiIsIHkgPSAiQnJhaW4gUmVnaW9uIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgI0kgd2lsbCBtYWtlIHRoZSBsZWdlbmQgc21hbGxlciBhbmQgcHV0IGl0IHVuZGVybmVhdGggdGhlIGdyYXBoICBiZWNhdXNlIGl0IGlzIHRvbyBiaWcKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKwogIGd1aWRlcyhjb2xvcj0ibm9uZSIpCgojIHNhbWUgcGxvdCBidXQgYWVzdGhldGljcyBvbmx5IGZvciBnZW5lcyBpbiAxNnAgcmVnaW9uCmdncGxvdChBSEJBX25vcm1lZF9waXZvdF9zaWdPTkxZLCBhZXMoeD1leHByZXNzaW9uLCB5PXJlZ2lvbiwgY29sb3I9aW5fMTZwX3JlZ2lvbikpICsgCiAgZ2VvbV9wb2ludCgpICsgCiAgbGFicyh0aXRsZSA9ICJOT1JNQUxJWkVEIHJlZ2lvbmFsIGV4cHJlc3Npb24gb2Ygc2lnbmlmaWNhbnQgZ2VuZXMgZnJvbSAxNnAgZGVsIG1ldGEtYW5hbHlzaXMiLCB4ID0gIk5vcm1hbGl6ZWQgRXhwcmVzc2lvbiIsIHkgPSAiQnJhaW4gUmVnaW9uIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgI0kgd2lsbCBtYWtlIHRoZSBsZWdlbmQgc21hbGxlciBhbmQgcHV0IGl0IHVuZGVybmVhdGggdGhlIGdyYXBoICBiZWNhdXNlIGl0IGlzIHRvbyBiaWcKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgCmBgYAoKTm93IEkgd2lsbCBtYXAgdGhlIG5vcm1hbGl6ZWQgQUhCQSBkYXRhIHRvIFNtcml0aGkncyBNUkkgZGF0YSwgd2hpY2ggaXMgaW4gYSBjc3YgZmlsZTogMTZwYW5hbHlzaXNfQkhfYWRqdXN0ZWQuY3N2CgpJbXBvcnRpbmcgbmVjZXNzYXJ5IGZpbGVzCmBgYHtyfQojIEltcG9ydGluZyBTbXJpdGhpJ3MgTVJJIGRhdGFzZXQKc2V0d2QoIi9Vc2Vycy90YW1teXJheS9EZXNrdG9wL2Fhcm9uX2xhYl8yMDI0L291dHB1dCIpCk1SSSA8LSByZWFkX2NzdigiMTZwYW5hbHlzaXNfQkhfYWRqdXN0ZWQuY3N2IikKCiMgT3V0c2lkZSBvZiBSLCBJIGhhdmUgbWFkZSBhIENTViBvZiBjb3JyZXNwb25kaW5nIEFIQkEgYW5kIFNtcml0aGkgTVJJIGRhdGEgcmVnaW9uIG5hbWVzLiBGaXJzdCBjb2x1bW4gaXMgQUhCQSBuYW1lcywgc2Vjb25kIGNvbHVtbiBpcyBNUkkgbmFtZXMuCiMgSW1wb3J0aW5nIHRoZSBkYXRhCnNldHdkKCIvVXNlcnMvdGFtbXlyYXkvRGVza3RvcC9hYXJvbl9sYWJfMjAyNC9DU1ZfZGF0YV9zaGVldHMiKQpzdGFuZGFyZF9yZWdpb25fbmFtZXMgPC0gcmVhZF9jc3YoIkFIQkFfTVJJX3JlZ2lvbl9uYW1lcy5jc3YiKQoKIyBSZW1lbWJlcmluZyBvdGhlciBmaWxlcyBJIHdpbGwgdXNlIGluIHRoZSBmb2xsb3dpbmcgY2h1bmtzCnNpeHRlZW5fcF8xMS4yX2dlbmVzICN2ZWN0b3Igb2YgYWxsIGdlbmVzIGluIDE2cCBsb2N1cwpgYGAKCgpUaWR5aW5nIFNtcml0aGkncyBNUkkgZGF0YQpgYGB7cn0KIyBXZSBkZWNpZGVkIHRoYXQgd2Ugb25seSB3YW50IHRvIHVzZSBtb2RlbCAzLCBTcGxpbmUgVENWIG1vZGVsIChkZWNpZGVkIHcgU21yaXRoaSBtZWV0aW5nIDgvMjQvMjQpCiMgV2UgYXJlIG9ubHkgdXNpbmcgdGhlIGRlbGV0aW9uIGRhdGEgZm9yIG5vdwpNUklfbW9kZWwzIDwtIE1SSSAlPiUKICBmaWx0ZXIoR2Vub3R5cGUgPT0gIkdlbm90eXBlMTZwRGVsZXRpb24uLi41IikKCiNNUkkgcmVnaW9ucyB0byByZW1vdmUuIEkgbWFkZSB0aGlzIGxpc3QgbWFudWFsbHkgdXNpbmcgZ29vZ2xlIHNoZWV0cyBhbmQgcmVmb3JtYXR0ZWQgaXQgZm9yIFIgdXNpbmcgY2hhdGdwdApNUklfcmVnaW9uc190b19yZW1vdmUgPC0gYygiTC5DZXJlYnJhbF9XTSIsICJMLmNlcmVicmFsX2NvcnRleCIsICJMLmxhdGVyYWxfdmVudHJpY2xlIiwgIkwuaW5mZXJpb3JfbGF0ZXJhbF92ZW50cmljbGUiLCAiTC5jZXJlYmVsbHVtX1dNIiwgIkwuY2VyZWJlbGx1bV9jb3J0ZXgiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIkwudGhhbGFtdXMiLCAiTC5jYXVkYXRlIiwgIkwucHV0YW1lbiIsICJMLnBhbGxpZHVtIiwgIkwuYWNjdW1iZW5zIiwgIkwuaGlwcG9jYW1wdXMiLCAiTC5hbXlnZGFsYSIsICJMLnZlbnRyYWxfREMiLCAiVGhpcmRfVmVudHJpY2xlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJGb3VydGhfVmVudHJpY2xlIiwgIkJyYWluc3RlbSIsICJDU0YiLCAiUi5DZXJlYnJhbF9XTSIsICJSLmNlcmVicmFsX2NvcnRleCIsICJSLmxhdGVyYWxfdmVudHJpY2xlIiwgIlIuaW5mZXJpb3JfbGF0ZXJhbF92ZW50cmljbGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIlIuY2VyZWJlbGx1bV9XTSIsICJSLmNlcmViZWxsdW1fY29ydGV4IiwgIlIudGhhbGFtdXMiLCAiUi5jYXVkYXRlIiwgIlIucHV0YW1lbiIsICJSLnBhbGxpZHVtIiwgIlIuaGlwcG9jYW1wdXMiLCAiUi5hbXlnZGFsYSIsICJSLmFjY3VtYmVucyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAiUi52ZW50cmFsX0RDIiwgIlIuY3R4X2Jhbmtzc3RzIiwgIlIuY3R4X2NhdWRhbGFudGVyaW9yY2luZ3VsYXRlIiwgIlIuY3R4X2NhdWRhbG1pZGRsZWZyb250YWwiLCAiUi5jdHhfY3VuZXVzIiwgIlIuY3R4X2VudG9yaGluYWwiLCAiUi5jdHhfZnVzaWZvcm0iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIlIuY3R4X2luZmVyaW9ycGFyaWV0YWwiLCAiUi5jdHhfaW5mZXJpb3J0ZW1wb3JhbCIsICJSLmN0eF9pc3RobXVzY2luZ3VsYXRlIiwgIlIuY3R4X2xhdGVyYWxvY2NpcGl0YWwiLCAiUi5jdHhfbGF0ZXJhbG9yYml0b2Zyb250YWwiLCAiUi5jdHhfbGluZ3VhbCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAiUi5jdHhfbWVkaWFsb3JiaXRvZnJvbnRhbCIsICJSLmN0eF9taWRkbGV0ZW1wb3JhbCIsICJSLmN0eF9wYXJhaGlwcG9jYW1wYWwiLCAiUi5jdHhfcGFyYWNlbnRyYWwiLCAiUi5jdHhfcGFyc29wZXJjdWxhcmlzIiwgIlIuY3R4X3BhcnNvcmJpdGFsaXMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIlIuY3R4X3BhcnN0cmlhbmd1bGFyaXMiLCAiUi5jdHhfcGVyaWNhbGNhcmluZSIsICJSLmN0eF9wb3N0Y2VudHJhbCIsICJSLmN0eF9wb3N0ZXJpb3JjaW5ndWxhdGUiLCAiUi5jdHhfcHJlY2VudHJhbCIsICJSLmN0eF9wcmVjdW5ldXMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIlIuY3R4X3Jvc3RyYWxhbnRlcmlvcmNpbmd1bGF0ZSIsICJSLmN0eF9yb3N0cmFsbWlkZGxlZnJvbnRhbCIsICJSLmN0eF9zdXBlcmlvcmZyb250YWwiLCAiUi5jdHhfc3VwZXJpb3JwYXJpZXRhbCIsICJSLmN0eF9zdXBlcmlvcnRlbXBvcmFsIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJSLmN0eF9zdXByYW1hcmdpbmFsIiwgIlIuY3R4X2Zyb250YWxwb2xlIiwgIlIuY3R4X3RlbXBvcmFscG9sZSIsICJSLmN0eF90cmFuc3ZlcnNldGVtcG9yYWwiLCAiUi5jdHhfaW5zdWxhIiwgImNHTVYiLCAiV01WIiwgInNHTVYiLCAiVmVudHJpY2xlcyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAiQ2VyZWJlbGx1bSIsICJBY2N1bWJlbnMiLCAiVmVudHJhbF9EaWVuY2VwaGFsb24iLCAiUGFsbGlkdW0iLCAiSGlwcG9jYW1wdXMiLCAiQ2F1ZGF0ZSIsICJDZXJlYnJhbF9XaGl0ZV9NYXR0ZXIiLCAiTGF0ZXJhbF9WZW50cmljbGUiLCAiQ2VyZWJyYWxfQ29ydGV4IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJUaGFsYW11cyIsICJQdXRhbWVuIiwgIkFteWdkYWxhIiwgIkNlcmViZWxsYXJfV2hpdGVfTWF0dGVyIiwgIkNlcmViZWxsYXJfQ29ydGV4IiwgIkluZmVyaW9yX0xhdGVyYWxfVmVudHJpY2xlIiwgImN0eF9iYW5rc3N0cyIsICJjdHhfY2F1ZGFsYW50ZXJpb3JjaW5ndWxhdGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgImN0eF9jYXVkYWxtaWRkbGVmcm9udGFsIiwgImN0eF9jdW5ldXMiLCAiY3R4X2VudG9yaGluYWwiLCAiY3R4X2Z1c2lmb3JtIiwgImN0eF9pbmZlcmlvcnBhcmlldGFsIiwgImN0eF9pbmZlcmlvcnRlbXBvcmFsIiwgImN0eF9pc3RobXVzY2luZ3VsYXRlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJjdHhfbGF0ZXJhbG9jY2lwaXRhbCIsICJjdHhfbGF0ZXJhbG9yYml0b2Zyb250YWwiLCAiY3R4X2xpbmd1YWwiLCAiY3R4X21lZGlhbG9yYml0b2Zyb250YWwiLCAiY3R4X21pZGRsZXRlbXBvcmFsIiwgImN0eF9wYXJhaGlwcG9jYW1wYWwiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgImN0eF9wYXJhY2VudHJhbCIsICJjdHhfcGFyc29wZXJjdWxhcmlzIiwgImN0eF9wYXJzb3JiaXRhbGlzIiwgImN0eF9wYXJzdHJpYW5ndWxhcmlzIiwgImN0eF9wZXJpY2FsY2FyaW5lIiwgImN0eF9wb3N0Y2VudHJhbCIsICJjdHhfcG9zdGVyaW9yY2luZ3VsYXRlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJjdHhfcHJlY2VudHJhbCIsICJjdHhfcHJlY3VuZXVzIiwgImN0eF9yb3N0cmFsYW50ZXJpb3JjaW5ndWxhdGUiLCAiY3R4X3Jvc3RyYWxtaWRkbGVmcm9udGFsIiwgImN0eF9zdXBlcmlvcmZyb250YWwiLCAiY3R4X3N1cGVyaW9ycGFyaWV0YWwiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgImN0eF9zdXBlcmlvcnRlbXBvcmFsIiwgImN0eF9zdXByYW1hcmdpbmFsIiwgImN0eF9mcm9udGFscG9sZSIsICJjdHhfdGVtcG9yYWxwb2xlIiwgImN0eF90cmFuc3ZlcnNldGVtcG9yYWwiLCAiY3R4X2luc3VsYSIpCgojIHJlbW92aW5nIHJvd3MgZm9yIHRoZSByZWdpb25zIHdlIGFyZW4ndCBpbmNsdWRpbmcKTVJJX21vZGVsM19sZWZ0SGVtIDwtIE1SSV9tb2RlbDMgJT4lCiAgZmlsdGVyKFZvbHVtZXRyaWNDb21wb25lbnQgJWluJSBNUklfcmVnaW9uc190b19yZW1vdmUgPT0gRkFMU0UpICU+JQogIHJlbmFtZShyZWdpb24gPSBWb2x1bWV0cmljQ29tcG9uZW50KQoKIyBOb3csIEkgd2FudCB0byB1c2UgdGhlIHN0YW5kYXJkIHJlZ2lvbgpzdGFuZGFyZF9yZWdpb25fbmFtZXMgPC0gc3RhbmRhcmRfcmVnaW9uX25hbWVzICU+JQogIHJlbmFtZShyZWdpb24gPSAibGVmdCBoZW1pc3BoZXJlIFNtcml0aGkgcmVnaW9ucyIsCiAgICAgICAgIG5ld19yZWdpb24gPSAiQUhCQSByZWdpb25zIikKCiMgVXNlIGxlZnRfam9pbiB0byBtYXAgdGhlIG5ldyBuYW1lcyBiYXNlZCBvbiB0aGUgcmVnaW9uIHZhcmlhYmxlCk1SSV9tb2RlbDNfbGVmdEhlbV9uZXdfcmVnaW9uTmFtZXMgPC0gTVJJX21vZGVsM19sZWZ0SGVtICU+JQogIGxlZnRfam9pbihzdGFuZGFyZF9yZWdpb25fbmFtZXMsIGJ5ID0gInJlZ2lvbiIpICU+JSAgICMgSm9pbiBiYXNlZCBvbiB0aGUgcmVnaW9uIHZhcmlhYmxlCiAgbXV0YXRlKHJlZ2lvbiA9IGlmZWxzZSghaXMubmEobmV3X3JlZ2lvbiksIG5ld19yZWdpb24sIHJlZ2lvbikpICU+JSAgICMgUmVwbGFjZSByZWdpb24gbmFtZXMgd2l0aCBuZXcgb25lcwogIHNlbGVjdCgtbmV3X3JlZ2lvbikgICMgUmVtb3ZlIHRoZSBleHRyYSBjb2x1bW4gaWYgbmVlZGVkCgpgYGAKCgpNZXJnaW5nIHRoZSBBSEJBIG5vcm1lZCB2YWx1ZXMgd2l0aCBTbXJpdGhpJ3MgTVJJIGRhdGEKYGBge3J9CkFIQkFfTVJJX21lcmdlZCA8LSBmdWxsX2pvaW4oQUhCQV9ub3JtZWRfcGl2b3Rfc2lnT05MWSwgTVJJX21vZGVsM19sZWZ0SGVtX25ld19yZWdpb25OYW1lcywgYnkgPSAicmVnaW9uIiwgbXVsdGlwbGUgPSAiYWxsIikKCkFIQkFfTVJJX21lcmdlZF9vcmdhbml6ZWQgPC0gQUhCQV9NUklfbWVyZ2VkICU+JQogIHNlbGVjdCgtR2Vub3R5cGUpCgpjb2xuYW1lcyhBSEJBX01SSV9tZXJnZWRfb3JnYW5pemVkKVszXSA8LSAiQUhCQV9leHByZXNzaW9uIgpjb2xuYW1lcyhBSEJBX01SSV9tZXJnZWRfb3JnYW5pemVkKVs4XSA8LSAidF92YWx1ZSIKCmBgYAoKCkV4cG9ydGluZyBhcyBjc3YgQUhCQV9NUklfbWVyZ2VkX29yZ2FuaXplZApgYGB7cn0Kc2V0d2QoIi9Vc2Vycy90YW1teXJheS9EZXNrdG9wL2Fhcm9uX2xhYl8yMDI0L0NTVl9kYXRhX3NoZWV0cyIpCndyaXRlX2NzdihBSEJBX01SSV9tZXJnZWRfb3JnYW5pemVkLCAiQUhCQV9NUklfbWVyZ2VkLmNzdiIpCmBgYAoKUGVhcnNvbiBjb3JyZWxhdGlvbiBhbmFseXNpcwpJIHdhbnQgdG8gZG8gYSBjb3JyZWxhdGlvbiBhbmFseXNpcyBiZXR3ZWVuIHRoZSBBSEJBIGV4cHJlc3Npb24gYW5kIHRoZSBNUkkgZGF0YQoKQ3JlYXRpbmcgZnVuY3Rpb25zIHRvIGNvbXB1dGUgY29ycmVsYXRpb24gYW5kIHAtdmFsdWUsIGNyZWF0ZWQgYnkgQ2hhdEdQVApgYGB7cn0KY29ycmVsYXRpb25fd2l0aF9wdmFsdWVfcGVhcnNvbiA8LSBmdW5jdGlvbih4LCB5KSB7CiAgdGVzdCA8LSBjb3IudGVzdCh4LCB5LCBtZXRob2QgPSAicGVhcnNvbiIpCiAgcmV0dXJuKGRhdGEuZnJhbWUoY29ycmVsYXRpb24gPSB0ZXN0JGVzdGltYXRlLCBwX3ZhbHVlID0gdGVzdCRwLnZhbHVlKSkKfQoKY29ycmVsYXRpb25fd2l0aF9wdmFsdWVfc3BlYXJtYW4gPC0gZnVuY3Rpb24oeCwgeSkgewogIHRlc3QgPC0gY29yLnRlc3QoeCwgeSwgbWV0aG9kID0gInNwZWFybWFuIikKICByZXR1cm4oZGF0YS5mcmFtZShjb3JyZWxhdGlvbiA9IHRlc3QkZXN0aW1hdGUsIHBfdmFsdWUgPSB0ZXN0JHAudmFsdWUpKQp9CmBgYAoKUnVubmluZyB0aGUgY29ycmVsYXRpb24gYW5hbHlzaXMKYGBge3J9CiMgR3JvdXAgYnkgZ2VuZV9zeW1ib2wgYW5kIGNvbXB1dGUgY29ycmVsYXRpb24gYmV0d2VlbiBBSEJBX2V4cHJlc3Npb24gYW5kIEVzdGltYXRlCmNvcl9yZXN1bHRzX0VzdGltYXRlX3BlYXJzb24gPC0gQUhCQV9NUklfbWVyZ2VkX29yZ2FuaXplZCAlPiUKICBncm91cF9ieShnZW5lX3N5bWJvbCkgJT4lCiAgc3VtbWFyaXplKGNvcnJlbGF0aW9uID0gY29yKEFIQkFfZXhwcmVzc2lvbiwgRXN0aW1hdGUsIG1ldGhvZCA9ICJwZWFyc29uIiksCiAgICAgICAgICAgIHBfdmFsdWUgPSBjb3JyZWxhdGlvbl93aXRoX3B2YWx1ZV9wZWFyc29uKEFIQkFfZXhwcmVzc2lvbiwgRXN0aW1hdGUpJHBfdmFsdWUpICU+JQogIG11dGF0ZShpbl8xNnBfbG9jdXMgPSBpZmVsc2UoZ2VuZV9zeW1ib2wgJWluJSBzaXh0ZWVuX3BfMTEuMl9nZW5lcywgIlllcyIsICJObyIpKQoKI1RyeWluZyBhIHNwZWFybWFuIGNvcnJlbGF0aW9uIGFuYWx5c2lzIGluc3RlYWQKY29yX3Jlc3VsdHNfRXN0aW1hdGVfc3BlYXJtYW4gPC0gQUhCQV9NUklfbWVyZ2VkX29yZ2FuaXplZCAlPiUKICBncm91cF9ieShnZW5lX3N5bWJvbCkgJT4lCiAgc3VtbWFyaXplKGNvcnJlbGF0aW9uID0gY29yKEFIQkFfZXhwcmVzc2lvbiwgRXN0aW1hdGUsIG1ldGhvZCA9ICJzcGVhcm1hbiIpLAogICAgICAgICAgICBwX3ZhbHVlID0gY29yLnRlc3QoQUhCQV9leHByZXNzaW9uLCBFc3RpbWF0ZSwgbWV0aG9kID0gInNwZWFybWFuIikkcC52YWx1ZSkgJT4lCiAgbXV0YXRlKGluXzE2cF9sb2N1cyA9IGlmZWxzZShnZW5lX3N5bWJvbCAlaW4lIHNpeHRlZW5fcF8xMS4yX2dlbmVzLCAiWWVzIiwgIk5vIikpCgojIERvaW5nIHRoZSBzYW1lIHRoaW5nIGZvciB0aGUgdCB2YWx1ZQojIFBlYXJzb24gY29ycmVsYXRpb24KY29yX3Jlc3VsdHNfdF92YWx1ZV9wZWFyc29uIDwtIEFIQkFfTVJJX21lcmdlZF9vcmdhbml6ZWQgJT4lCiAgZ3JvdXBfYnkoZ2VuZV9zeW1ib2wpICU+JQogIHN1bW1hcml6ZShjb3JyZWxhdGlvbiA9IGNvcihBSEJBX2V4cHJlc3Npb24sIHRfdmFsdWUsIG1ldGhvZCA9ICJwZWFyc29uIiksCiAgICAgICAgICAgIHBfdmFsdWUgPSBjb3JyZWxhdGlvbl93aXRoX3B2YWx1ZV9wZWFyc29uKEFIQkFfZXhwcmVzc2lvbiwgdF92YWx1ZSkkcF92YWx1ZSkgJT4lCiAgbXV0YXRlKGluXzE2cF9sb2N1cyA9IGlmZWxzZShnZW5lX3N5bWJvbCAlaW4lIHNpeHRlZW5fcF8xMS4yX2dlbmVzLCAiWWVzIiwgIk5vIikpCgojU3BlYXJtYW4gY29ycmVsYXRpb24KY29yX3Jlc3VsdHNfdF92YWx1ZV9zcGVhcm1hbiA8LSBBSEJBX01SSV9tZXJnZWRfb3JnYW5pemVkICU+JQogIGdyb3VwX2J5KGdlbmVfc3ltYm9sKSAlPiUKICBzdW1tYXJpemUoY29ycmVsYXRpb24gPSBjb3IoQUhCQV9leHByZXNzaW9uLCB0X3ZhbHVlLCBtZXRob2QgPSAic3BlYXJtYW4iKSwKICAgICAgICAgICAgcF92YWx1ZSA9IGNvci50ZXN0KEFIQkFfZXhwcmVzc2lvbiwgdF92YWx1ZSwgbWV0aG9kID0gInNwZWFybWFuIikkcC52YWx1ZSkgJT4lCiAgbXV0YXRlKGluXzE2cF9sb2N1cyA9IGlmZWxzZShnZW5lX3N5bWJvbCAlaW4lIHNpeHRlZW5fcF8xMS4yX2dlbmVzLCAiWWVzIiwgIk5vIikpCmBgYAoKCkV4cG9ydGluZyB0aGUgY29ycmVsYXRpb24gYW5hbHlzaXMgZGF0YWZyYW1lcyB0byBDU1YgZmlsZXMKYGBge3J9CnNldHdkKCIvVXNlcnMvdGFtbXlyYXkvRGVza3RvcC9hYXJvbl9sYWJfMjAyNC9DU1ZfZGF0YV9zaGVldHMiKQp3cml0ZV9jc3YoY29yX3Jlc3VsdHNfRXN0aW1hdGVfcGVhcnNvbiwgIkFIQkFfTVJJX2NvcnJlbGF0aW9uX0VzdGltYXRlX1BlYXJzb24uY3N2IikKd3JpdGVfY3N2KGNvcl9yZXN1bHRzX0VzdGltYXRlX3NwZWFybWFuLCAiQUhCQV9NUklfY29ycmVsYXRpb25fRXN0aW1hdGVfU3BlYXJtYW4uY3N2IikKd3JpdGVfY3N2KGNvcl9yZXN1bHRzX3RfdmFsdWVfcGVhcnNvbiwgIkFIQkFfTVJJX2NvcnJlbGF0aW9uX3RfdmFsdWVfUGVhcnNvbi5jc3YiKQp3cml0ZV9jc3YoY29yX3Jlc3VsdHNfdF92YWx1ZV9zcGVhcm1hbiwgIkFIQkFfTVJJX2NvcnJlbGF0aW9uX3RfdmFsdWVfU3BlYXJtYW4uY3N2IikKYGBgCgoKTm93LCBJIHdhbnQgdG8gdmlzdWFsaXplIHRoZSBjb3JyZWxhdGlvbiBkYXRhCmBgYHtyfQojU2NhdHRlcnBsb3Qgc2hvd2luZyByZWxhdGlvbnNoaXAgYmV0d2VlbiBwIHZhbHVlIGFuZCBjb3JyZWxhdGlvbiwgbm90IHN1cGVyIHVzZWZ1bCBidXQgZWR1Y2F0aW9uYWwgZm9yIG1lIQpnZ3Bsb3QoY29yX3Jlc3VsdHNfdF92YWx1ZV9zcGVhcm1hbiwgYWVzKHg9cF92YWx1ZSwgeT1jb3JyZWxhdGlvbiwgY29sb3I9aW5fMTZwX2xvY3VzKSkgKwogIGdlb21fcG9pbnQoKSArCiAgbGFicyh0aXRsZSA9ICJTcGVhcm1hbiBjb3JyZWxhdGlvbiBvZiB0LXZhbHVlIiwKICAgICAgIHggPSAicCB2YWx1ZSIsCiAgICAgICB5ID0gImNvcnJlbGF0aW9uIikgKwogIHRoZW1lX21pbmltYWwoKSArIAogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSAwLjA1KSkKCiNtYWtpbmcgYSBkZW5zaXR5IGN1cnZlIGluc3RlYWQ/CmdncGxvdChjb3JfcmVzdWx0c190X3ZhbHVlX3NwZWFybWFuLCBhZXMoeD1jb3JyZWxhdGlvbiwgY29sb3I9aW5fMTZwX2xvY3VzKSkgKwogIGdlb21fZGVuc2l0eSgpICsKICBsYWJzKHRpdGxlID0gIlNwZWFybWFuIGNvcnJlbGF0aW9uIG9mIHQtdmFsdWUiLAogICAgICAgeCA9ICJDb3JyZWxhdGlvbiBDb2VmZmljaWVudCIsCiAgICAgICB5ID0gIkRlbnNpdHkiKSArCiAgdGhlbWVfbWluaW1hbCgpCgojIG1ha2luZyBhIGhpc3RvZ3JhbSBpbnN0ZWFkCmdncGxvdChjb3JfcmVzdWx0c190X3ZhbHVlX3NwZWFybWFuLCBhZXMoeD0gYWJzKGNvcnJlbGF0aW9uKSwgZmlsbD1pbl8xNnBfbG9jdXMpKSArCiAgZ2VvbV9oaXN0b2dyYW0ocG9zaXRpb24gPSAiaWRlbnRpdHkiLCBhbHBoYSA9IDAuNikgKwogIGxhYnModGl0bGUgPSAiU3BlYXJtYW4gY29ycmVsYXRpb24gb2YgdC12YWx1ZSIsCiAgICAgICB4ID0gIkFic29sdXRlIFZhbHVlIG9mIENvcnJlbGF0aW9uIENvZWZmaWNpZW50IiwKICAgICAgIHkgPSAiRnJlcXVlbmN5IikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgeGxpbSgwLCAwLjYpICsgeWxpbSgwLCA4KQoKZ2dwbG90KGNvcl9yZXN1bHRzX0VzdGltYXRlX3NwZWFybWFuLCBhZXMoeD1hYnMoY29ycmVsYXRpb24pLCBmaWxsPWluXzE2cF9sb2N1cykpICsKICBnZW9tX2hpc3RvZ3JhbShwb3NpdGlvbiA9ICJpZGVudGl0eSIsIGFscGhhID0gMC42KSArCiAgbGFicyh0aXRsZSA9ICJTcGVhcm1hbiBjb3JyZWxhdGlvbiBvZiBFc3RpbWF0ZSh+ZWZmZWN0IHNpemUpIiwKICAgICAgIHggPSAiQWJzb2x1dGUgVmFsdWUgb2YgQ29ycmVsYXRpb24gQ29lZmZpY2llbnQiLAogICAgICAgeSA9ICJGcmVxdWVuY3kiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB4bGltKDAsIDAuNikgKyB5bGltKDAsIDgpCmBgYAoKTm93IEkgd2FudCB0byBwbG90IHRoZSBkYXRhCmBgYHtyfQpsaWJyYXJ5KCJnZ3B1YnIiKQpsaWJyYXJ5KHBsb3RseSkKYGBgCgpgYGB7cn0KI01ha2luZyBhIGh1Z2UgcGxvdCB3aXRoIGEgbG90IG9mIGxpdHRsZSBwbG90cyBpbnNpZGUgKGNvdXJ0ZXN5IG9mIGZhY2V0X3dyYXApIG9mIGFsbCBnZW5lcwpzY2F0dGVyX3Bsb3RfZXN0aW1hdGUgPC0gZ2dwbG90KEFIQkFfTVJJX21lcmdlZF9vcmdhbml6ZWQsIGFlcyh4ID0gQUhCQV9leHByZXNzaW9uLCB5ID0gRXN0aW1hdGUsIGNvbG9yID0gcmVnaW9uKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDAuMSkgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJibHVlIiwgbGluZXdpZHRoID0gMC41KSArICAjIEFkZCBhIGxpbmUgb2YgYmVzdCBmaXQgKGxpbmVhciByZWdyZXNzaW9uKQogIGxhYnModGl0bGUgPSAiU2NhdHRlciBwbG90cyBvZiBBSEJBIEV4cHJlc3Npb24gdnMgRXN0aW1hdGUgZm9yIGFsbCBHZW5lcyIsCiAgICAgICB4ID0gIkFIQkEgRXhwcmVzc2lvbiIsCiAgICAgICB5ID0gIkVzdGltYXRlIikgKwogIGZhY2V0X3dyYXAofiBnZW5lX3N5bWJvbCwgc2NhbGVzID0gImZyZWUiKSArICAjIFNlcGFyYXRlIHBsb3RzIGZvciBlYWNoIGdlbmUKICB0aGVtZV9taW5pbWFsKCkgKwogIHhsaW0oMCwgMSkgKyB5bGltKC0wLjcsIDAuNykgIysKICBzdGF0X2NvcihhZXMobGFiZWwgPSBwYXN0ZSguLnIubGFiZWwuLiwgc2VwID0gIn5gLGB+IikpLCAKICAgICAgICAgbWV0aG9kID0gInBlYXJzb24iLCBsYWJlbC54ID0gMywgbGFiZWwueSA9IDApICAjIEFkZCBjb3JyZWxhdGlvbiBjb2VmZmljaWVudHMgdG8gdGhlIHBsb3QKCiMgQ29udmVydCB0byBhIHBsb3RseSBvYmplY3QKaW50ZXJhY3RpdmVfcGxvdF9lc3RpbWF0ZSA8LSBnZ3Bsb3RseShzY2F0dGVyX3Bsb3RfZXN0aW1hdGUsIHRvb2x0aXAgPSBjKCJ0ZXh0IikpCmludGVyYWN0aXZlX3Bsb3RfZXN0aW1hdGUgIyBEaXNwbGF5IHRoZSBpbnRlcmFjdGl2ZSBwbG90CgojRG9pbmcgdGhlIHNhbWUgcGxvdCwgYnV0IGZvciB0LXZhbHVlCnNjYXR0ZXJfcGxvdF90X3ZhbHVlIDwtIGdncGxvdChBSEJBX01SSV9tZXJnZWRfb3JnYW5pemVkLCBhZXMoeCA9IEFIQkFfZXhwcmVzc2lvbiwgeSA9IEVzdGltYXRlLCBjb2xvciA9IHJlZ2lvbikpICsKICBnZW9tX3BvaW50KHNpemUgPSAwLjEpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAiYmx1ZSIsIGxpbmV3aWR0aCA9IDAuNSkgKyAgIyBBZGQgYSBsaW5lIG9mIGJlc3QgZml0IChsaW5lYXIgcmVncmVzc2lvbikKICBsYWJzKHRpdGxlID0gIlNjYXR0ZXIgcGxvdHMgb2YgQUhCQSBFeHByZXNzaW9uIHZzIEVzdGltYXRlIGZvciBhbGwgR2VuZXMiLAogICAgICAgeCA9ICJBSEJBIEV4cHJlc3Npb24iLAogICAgICAgeSA9ICJFc3RpbWF0ZSIpICsKICBmYWNldF93cmFwKH4gZ2VuZV9zeW1ib2wsIHNjYWxlcyA9ICJmcmVlIikgKyAgIyBTZXBhcmF0ZSBwbG90cyBmb3IgZWFjaCBnZW5lCiAgdGhlbWVfbWluaW1hbCgpICsKICBzdGF0X2NvcihhZXMobGFiZWwgPSBwYXN0ZSguLnIubGFiZWwuLiwgc2VwID0gIn5gLGB+IikpLCAKICAgICAgICAgICBtZXRob2QgPSAicGVhcnNvbiIsIGxhYmVsLnggPSAzLCBsYWJlbC55ID0gMCkgICMgQWRkIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50cyB0byB0aGUgcGxvdAoKIyBDb252ZXJ0IHRvIGEgcGxvdGx5IG9iamVjdAppbnRlcmFjdGl2ZV9wbG90X3RfdmFsdWUgPC0gZ2dwbG90bHkoc2NhdHRlcl9wbG90X3RfdmFsdWUsIHRvb2x0aXAgPSBjKCJ0ZXh0IikpCmludGVyYWN0aXZlX3Bsb3RfdF92YWx1ZSAjIERpc3BsYXkgdGhlIGludGVyYWN0aXZlIHBsb3QKYGBgCgoKRG9pbmcgdGhlIGFib3ZlIHBsb3R0aW5nIGZvciB0aGUgMTZwIGdlbmVzIG9ubHkKYGBge3J9CiMgRG9pbmcgdGhlIGFib3ZlIHBsb3R0aW5nIGZvciB0aGUgTk9OIDE2cCBnZW5lcyAtLS0tCkFIQkFfTVJJX21lcmdlZF9vcmdhbml6ZWRfTk9UX0lOXzE2cF9sb2N1cyA8LSBBSEJBX01SSV9tZXJnZWRfb3JnYW5pemVkICU+JSBmaWx0ZXIoaW5fMTZwX3JlZ2lvbiA9PSAiTm8iKQoKc2NhdHRlcl9wbG90X05PVF8xNnBfZ2VuZXMgPC0gZ2dwbG90KEFIQkFfTVJJX21lcmdlZF9vcmdhbml6ZWRfTk9UX0lOXzE2cF9sb2N1cywgYWVzKHggPSBBSEJBX2V4cHJlc3Npb24sIHkgPSBFc3RpbWF0ZSwgY29sb3IgPSByZWdpb24pKSArCiAgZ2VvbV9wb2ludChzaXplID0gMC4xKSArIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gImJsdWUiLCBsaW5ld2lkdGggPSAwLjUsIGZ1bGxyYW5nZSA9IFRSVUUpICsgICMgQWRkIGEgbGluZSBvZiBiZXN0IGZpdCAobGluZWFyIHJlZ3Jlc3Npb24pCiAgbGFicyh0aXRsZSA9ICJTY2F0dGVyIHBsb3RzIG9mIEFIQkEgRXhwcmVzc2lvbiB2cyBFc3RpbWF0ZSBmb3IgR2VuZXMgTk9UIGluIDE2cCBsb2N1cyIsCiAgICAgICB4ID0gIkFIQkEgRXhwcmVzc2lvbiIsCiAgICAgICB5ID0gIkVzdGltYXRlIikgKwogIGZhY2V0X3dyYXAofiBnZW5lX3N5bWJvbCwgc2NhbGVzID0gImZyZWUiKSArICAjIFNlcGFyYXRlIHBsb3RzIGZvciBlYWNoIGdlbmUKICB0aGVtZV9taW5pbWFsKCkgKwogIHN0YXRfY29yKGFlcyhsYWJlbCA9IHBhc3RlKC4uci5sYWJlbC4uLCBzZXAgPSAifmAsYH4iKSksIAogICAgICAgICAgIG1ldGhvZCA9ICJwZWFyc29uIiwgbGFiZWwueCA9IDMsIGxhYmVsLnkgPSAwKSArICMgQWRkIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50cyB0byB0aGUgcGxvdAogIHhsaW0oMCwgMSkgICMgQWRqdXN0IGF4aXMgbGltaXRzCiMgQ29udmVydCB0byBhIHBsb3RseSBvYmplY3QKaW50ZXJhY3RpdmVfcGxvdF9OT1RfMTZwX2dlbmVzIDwtIGdncGxvdGx5KHNjYXR0ZXJfcGxvdF9OT1RfMTZwX2dlbmVzLCB0b29sdGlwID0gYygidGV4dCIpKQoKIyBEaXNwbGF5IHRoZSBpbnRlcmFjdGl2ZSBwbG90CmludGVyYWN0aXZlX3Bsb3RfTk9UXzE2cF9nZW5lcwpgYGAKCgpBZGRpbmcgY29ycmVsYXRpb24gY29lZmZpY2llbmNpZXMgYW5kIHAgdmFsdWVzIHRvIHBsb3RzCjEuIE1ha2luZyBuZXcgZGF0YWZyYW13IHdpdGggZmFjZXQgbGFiZWxzCmBgYHtyfQojIE1lcmdlIG1haW4gZGF0YSB3aXRoIGNvcnJlbGF0aW9uIHJlc3VsdHMKcGxvdF9kYXRhX3RfdmFsdWVfc3BlYXJtYW4gPC0gQUhCQV9NUklfbWVyZ2VkX29yZ2FuaXplZCAlPiUKICBsZWZ0X2pvaW4oY29yX3Jlc3VsdHNfdF92YWx1ZV9zcGVhcm1hbiwgYnkgPSAiZ2VuZV9zeW1ib2wiKSAlPiUgIyBNZXJnZSBieSBnZW5lX3N5bWJvbAogIG11dGF0ZShmYWNldF9sYWJlbCA9IHBhc3RlMChnZW5lX3N5bWJvbCwgIlxuIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ8IFI6ICIsIHJvdW5kKGNvcnJlbGF0aW9uLCAyKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIsIHA6ICIsIHJvdW5kKHBfdmFsdWUsIDMpKSkKYGBgCgoKMi4gcmVwbG90dGluZyBkYXRhCmBgYHtyfQpnZ3Bsb3QocGxvdF9kYXRhX3RfdmFsdWVfc3BlYXJtYW4sIGFlcyh4ID0gQUhCQV9leHByZXNzaW9uLCB5ID0gdF92YWx1ZSwgY29sb3IgPSByZWdpb24pKSArCiAgZ2VvbV9wb2ludChzaXplID0gMC4xKSArIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gImJsdWUiLCBsaW5ld2lkdGggPSAwLjUsIGZ1bGxyYW5nZSA9IFRSVUUpICsgICMgQWRkIGEgbGluZSBvZiBiZXN0IGZpdCAobGluZWFyIHJlZ3Jlc3Npb24pCiAgbGFicyh0aXRsZSA9ICJTY2F0dGVyIHBsb3RzIG9mIEFIQkEgRXhwcmVzc2lvbiB2cyB0LXZhbHVlIGZvciBhbGwgR2VuZXMiLAogICAgICAgeCA9ICJBSEJBIEV4cHJlc3Npb24iLAogICAgICAgeSA9ICJ0LXZhbHVlIikgKwogIGZhY2V0X3dyYXAofiBmYWNldF9sYWJlbCwgc2NhbGVzID0gImZyZWUiKSArICAjIFVzZSB0aGUgY3VzdG9tIGZhY2V0IGxhYmVsCiAgdGhlbWVfbWluaW1hbCgpICsKICB4bGltKDAsIDEpICMrIHlsaW0oLTAuNywgMC43KSAgIyBBZGp1c3QgYXhpcyBsaW1pdHMKYGBgCgoKCgoKCgo=